From 2f90768662711ced66f7a78c2bf13ae27128c05d Mon Sep 17 00:00:00 2001 From: Matt Keeler Date: Thu, 21 Jun 2018 10:49:35 -0400 Subject: [PATCH] Vendor the vault api --- vendor/cloud.google.com/go/LICENSE | 2 +- vendor/cloud.google.com/go/civil/civil.go | 277 + vendor/github.com/Jeffail/gabs/LICENSE | 19 + vendor/github.com/Jeffail/gabs/README.md | 315 + vendor/github.com/Jeffail/gabs/gabs.go | 579 + vendor/github.com/Jeffail/gabs/gabs_logo.png | 3 + vendor/github.com/SAP/go-hdb/LICENSE | 201 + vendor/github.com/SAP/go-hdb/NOTICE | 5 + vendor/github.com/SAP/go-hdb/driver/bytes.go | 43 + .../github.com/SAP/go-hdb/driver/connector.go | 287 + .../github.com/SAP/go-hdb/driver/converter.go | 363 + .../github.com/SAP/go-hdb/driver/decimal.go | 377 + vendor/github.com/SAP/go-hdb/driver/doc.go | 18 + vendor/github.com/SAP/go-hdb/driver/driver.go | 542 + .../SAP/go-hdb/driver/driver_future.go | 162 + .../SAP/go-hdb/driver/driver_go1.10.go | 32 + .../SAP/go-hdb/driver/driver_legacy.go | 507 + vendor/github.com/SAP/go-hdb/driver/dsn.go | 64 + vendor/github.com/SAP/go-hdb/driver/error.go | 39 + .../SAP/go-hdb/driver/identifier.go | 49 + vendor/github.com/SAP/go-hdb/driver/lob.go | 94 + .../SAP/go-hdb/driver/sqltrace/doc.go | 18 + .../SAP/go-hdb/driver/sqltrace/sqltrace.go | 78 + vendor/github.com/SAP/go-hdb/driver/time.go | 44 + .../SAP/go-hdb/internal/bufio/bufio.go | 414 + .../SAP/go-hdb/internal/protocol/clientid.go | 55 + .../SAP/go-hdb/internal/protocol/command.go | 47 + .../go-hdb/internal/protocol/connectoption.go | 57 + .../internal/protocol/connectoption_string.go | 41 + .../internal/protocol/connectoptions.go | 109 + .../SAP/go-hdb/internal/protocol/datatype.go | 38 + .../internal/protocol/datatype_string.go | 16 + .../SAP/go-hdb/internal/protocol/doc.go | 20 + .../SAP/go-hdb/internal/protocol/endianess.go | 26 + .../internal/protocol/endianess_string.go | 16 + .../SAP/go-hdb/internal/protocol/error.go | 204 + .../go-hdb/internal/protocol/errorlevel.go | 40 + .../SAP/go-hdb/internal/protocol/fetchsize.go | 46 + .../SAP/go-hdb/internal/protocol/field.go | 774 + .../go-hdb/internal/protocol/functioncode.go | 60 + .../internal/protocol/functioncode_string.go | 16 + .../SAP/go-hdb/internal/protocol/init.go | 198 + .../go-hdb/internal/protocol/littleendian.go | 23 + .../SAP/go-hdb/internal/protocol/lob.go | 507 + .../SAP/go-hdb/internal/protocol/message.go | 75 + .../go-hdb/internal/protocol/messagetype.go | 49 + .../internal/protocol/messagetype_string.go | 44 + .../SAP/go-hdb/internal/protocol/option.go | 188 + .../SAP/go-hdb/internal/protocol/parameter.go | 389 + .../SAP/go-hdb/internal/protocol/part.go | 144 + .../SAP/go-hdb/internal/protocol/partkind.go | 79 + .../internal/protocol/partkind_string.go | 72 + .../SAP/go-hdb/internal/protocol/querytype.go | 29 + .../internal/protocol/querytype_string.go | 16 + .../SAP/go-hdb/internal/protocol/result.go | 294 + .../go-hdb/internal/protocol/rowsaffected.go | 72 + .../go-hdb/internal/protocol/scramsha256.go | 265 + .../SAP/go-hdb/internal/protocol/segment.go | 174 + .../go-hdb/internal/protocol/segmentkind.go | 28 + .../internal/protocol/segmentkind_string.go | 25 + .../SAP/go-hdb/internal/protocol/session.go | 975 + .../SAP/go-hdb/internal/protocol/sniffer.go | 203 + .../internal/protocol/statementcontext.go | 60 + .../internal/protocol/statementcontexttype.go | 26 + .../protocol/statementcontexttype_string.go | 17 + .../go-hdb/internal/protocol/statementid.go | 66 + .../go-hdb/internal/protocol/tableresult.go | 52 + .../SAP/go-hdb/internal/protocol/time.go | 64 + .../SAP/go-hdb/internal/protocol/topology.go | 85 + .../internal/protocol/topologyoption.go | 36 + .../protocol/topologyoption_string.go | 17 + .../internal/protocol/transactionflags.go | 60 + .../internal/protocol/transactionflagtype.go | 32 + .../protocol/transactionflagtype_string.go | 16 + .../SAP/go-hdb/internal/protocol/typecode.go | 159 + .../internal/protocol/typecode_string.go | 48 + .../go-hdb/internal/unicode/cesu8/cesu8.go | 240 + .../SAP/go-hdb/internal/unicode/unicode.go | 111 + vendor/github.com/SermoDigital/jose/LICENSE | 22 + vendor/github.com/SermoDigital/jose/README.md | 40 + vendor/github.com/SermoDigital/jose/_test.sh | 8 + vendor/github.com/SermoDigital/jose/base64.go | 44 + .../SermoDigital/jose/crypto/doc.go | 4 + .../SermoDigital/jose/crypto/ecdsa.go | 117 + .../SermoDigital/jose/crypto/ecdsa_utils.go | 48 + .../SermoDigital/jose/crypto/errors.go | 9 + .../SermoDigital/jose/crypto/hmac.go | 81 + .../SermoDigital/jose/crypto/none.go | 72 + .../SermoDigital/jose/crypto/rsa.go | 80 + .../SermoDigital/jose/crypto/rsa_pss.go | 96 + .../SermoDigital/jose/crypto/rsa_utils.go | 70 + .../SermoDigital/jose/crypto/signature.go | 36 + .../jose/crypto/signing_method.go | 24 + vendor/github.com/SermoDigital/jose/doc.go | 3 + vendor/github.com/SermoDigital/jose/header.go | 124 + .../SermoDigital/jose/jws/claims.go | 190 + .../github.com/SermoDigital/jose/jws/doc.go | 2 + .../SermoDigital/jose/jws/errors.go | 62 + .../github.com/SermoDigital/jose/jws/jws.go | 490 + .../SermoDigital/jose/jws/jws_serialize.go | 132 + .../SermoDigital/jose/jws/jws_validate.go | 203 + .../github.com/SermoDigital/jose/jws/jwt.go | 115 + .../SermoDigital/jose/jws/payload.go | 52 + .../SermoDigital/jose/jws/rawbase64.go | 28 + .../SermoDigital/jose/jws/signing_methods.go | 63 + .../SermoDigital/jose/jwt/claims.go | 274 + .../github.com/SermoDigital/jose/jwt/doc.go | 2 + vendor/github.com/SermoDigital/jose/jwt/eq.go | 47 + .../SermoDigital/jose/jwt/errors.go | 28 + .../github.com/SermoDigital/jose/jwt/jwt.go | 144 + vendor/github.com/SermoDigital/jose/time.go | 6 + .../asaskevich/govalidator/CONTRIBUTING.md | 63 + .../github.com/asaskevich/govalidator/LICENSE | 21 + .../asaskevich/govalidator/README.md | 490 + .../asaskevich/govalidator/arrays.go | 58 + .../asaskevich/govalidator/converter.go | 64 + .../asaskevich/govalidator/error.go | 36 + .../asaskevich/govalidator/numerics.go | 97 + .../asaskevich/govalidator/patterns.go | 97 + .../asaskevich/govalidator/types.go | 616 + .../asaskevich/govalidator/utils.go | 264 + .../asaskevich/govalidator/validator.go | 1220 + .../asaskevich/govalidator/wercker.yml | 15 + .../denisenkom/go-mssqldb/LICENSE.txt | 27 + .../denisenkom/go-mssqldb/README.md | 205 + .../denisenkom/go-mssqldb/appveyor.yml | 48 + .../github.com/denisenkom/go-mssqldb/buf.go | 258 + .../denisenkom/go-mssqldb/bulkcopy.go | 554 + .../denisenkom/go-mssqldb/bulkcopy_sql.go | 93 + .../denisenkom/go-mssqldb/decimal.go | 131 + .../github.com/denisenkom/go-mssqldb/doc.go | 14 + .../github.com/denisenkom/go-mssqldb/error.go | 73 + .../go-mssqldb/internal/cp/charset.go | 113 + .../go-mssqldb/internal/cp/collation.go | 20 + .../go-mssqldb/internal/cp/cp1250.go | 262 + .../go-mssqldb/internal/cp/cp1251.go | 262 + .../go-mssqldb/internal/cp/cp1252.go | 262 + .../go-mssqldb/internal/cp/cp1253.go | 262 + .../go-mssqldb/internal/cp/cp1254.go | 262 + .../go-mssqldb/internal/cp/cp1255.go | 262 + .../go-mssqldb/internal/cp/cp1256.go | 262 + .../go-mssqldb/internal/cp/cp1257.go | 262 + .../go-mssqldb/internal/cp/cp1258.go | 262 + .../go-mssqldb/internal/cp/cp437.go | 262 + .../go-mssqldb/internal/cp/cp850.go | 262 + .../go-mssqldb/internal/cp/cp874.go | 262 + .../go-mssqldb/internal/cp/cp932.go | 7988 ++++++ .../go-mssqldb/internal/cp/cp936.go | 22055 ++++++++++++++++ .../go-mssqldb/internal/cp/cp949.go | 17312 ++++++++++++ .../go-mssqldb/internal/cp/cp950.go | 13767 ++++++++++ .../github.com/denisenkom/go-mssqldb/log.go | 30 + .../github.com/denisenkom/go-mssqldb/mssql.go | 877 + .../denisenkom/go-mssqldb/mssql_go110.go | 50 + .../denisenkom/go-mssqldb/mssql_go19.go | 175 + .../denisenkom/go-mssqldb/mssql_go19pre.go | 16 + .../github.com/denisenkom/go-mssqldb/net.go | 103 + .../github.com/denisenkom/go-mssqldb/ntlm.go | 283 + .../denisenkom/go-mssqldb/parser.go | 257 + .../github.com/denisenkom/go-mssqldb/rpc.go | 89 + .../denisenkom/go-mssqldb/sspi_windows.go | 266 + .../github.com/denisenkom/go-mssqldb/tds.go | 1367 + .../github.com/denisenkom/go-mssqldb/token.go | 806 + .../denisenkom/go-mssqldb/token_string.go | 53 + .../github.com/denisenkom/go-mssqldb/tran.go | 110 + .../github.com/denisenkom/go-mssqldb/types.go | 1561 ++ .../denisenkom/go-mssqldb/uniqueidentifier.go | 74 + vendor/github.com/fatih/structs/LICENSE | 21 + vendor/github.com/fatih/structs/README.md | 163 + vendor/github.com/fatih/structs/field.go | 141 + vendor/github.com/fatih/structs/structs.go | 584 + vendor/github.com/fatih/structs/tags.go | 32 + vendor/github.com/go-sql-driver/mysql/AUTHORS | 89 + .../go-sql-driver/mysql/CHANGELOG.md | 167 + .../go-sql-driver/mysql/CONTRIBUTING.md | 23 + vendor/github.com/go-sql-driver/mysql/LICENSE | 373 + .../github.com/go-sql-driver/mysql/README.md | 490 + vendor/github.com/go-sql-driver/mysql/auth.go | 420 + .../github.com/go-sql-driver/mysql/buffer.go | 147 + .../go-sql-driver/mysql/collations.go | 251 + .../go-sql-driver/mysql/connection.go | 654 + .../github.com/go-sql-driver/mysql/const.go | 174 + .../github.com/go-sql-driver/mysql/driver.go | 162 + vendor/github.com/go-sql-driver/mysql/dsn.go | 611 + .../github.com/go-sql-driver/mysql/errors.go | 65 + .../github.com/go-sql-driver/mysql/fields.go | 194 + .../github.com/go-sql-driver/mysql/infile.go | 182 + .../github.com/go-sql-driver/mysql/packets.go | 1301 + .../github.com/go-sql-driver/mysql/result.go | 22 + vendor/github.com/go-sql-driver/mysql/rows.go | 216 + .../go-sql-driver/mysql/statement.go | 211 + .../go-sql-driver/mysql/transaction.go | 31 + .../github.com/go-sql-driver/mysql/utils.go | 755 + vendor/github.com/gocql/gocql/AUTHORS | 108 + vendor/github.com/gocql/gocql/CONTRIBUTING.md | 78 + vendor/github.com/gocql/gocql/LICENSE | 27 + vendor/github.com/gocql/gocql/README.md | 215 + .../gocql/gocql/address_translators.go | 26 + vendor/github.com/gocql/gocql/cluster.go | 202 + vendor/github.com/gocql/gocql/compressor.go | 28 + vendor/github.com/gocql/gocql/conn.go | 1200 + .../github.com/gocql/gocql/connectionpool.go | 579 + vendor/github.com/gocql/gocql/control.go | 482 + vendor/github.com/gocql/gocql/debug_off.go | 5 + vendor/github.com/gocql/gocql/debug_on.go | 5 + vendor/github.com/gocql/gocql/doc.go | 9 + vendor/github.com/gocql/gocql/errors.go | 116 + vendor/github.com/gocql/gocql/events.go | 293 + vendor/github.com/gocql/gocql/filters.go | 57 + vendor/github.com/gocql/gocql/frame.go | 1957 ++ vendor/github.com/gocql/gocql/fuzz.go | 33 + vendor/github.com/gocql/gocql/go.mod | 7 + vendor/github.com/gocql/gocql/go.modverify | 3 + vendor/github.com/gocql/gocql/helpers.go | 365 + vendor/github.com/gocql/gocql/host_source.go | 692 + .../github.com/gocql/gocql/host_source_gen.go | 45 + .../gocql/gocql/install_test_deps.sh | 16 + vendor/github.com/gocql/gocql/integration.sh | 87 + .../gocql/gocql/internal/lru/lru.go | 127 + .../gocql/gocql/internal/murmur/murmur.go | 135 + .../gocql/internal/murmur/murmur_unsafe.go | 15 + .../gocql/gocql/internal/streams/streams.go | 140 + vendor/github.com/gocql/gocql/logger.go | 30 + vendor/github.com/gocql/gocql/marshal.go | 2216 ++ vendor/github.com/gocql/gocql/metadata.go | 1100 + vendor/github.com/gocql/gocql/policies.go | 854 + .../github.com/gocql/gocql/prepared_cache.go | 64 + .../github.com/gocql/gocql/query_executor.go | 99 + vendor/github.com/gocql/gocql/ring.go | 152 + vendor/github.com/gocql/gocql/session.go | 1787 ++ vendor/github.com/gocql/gocql/token.go | 220 + vendor/github.com/gocql/gocql/topology.go | 212 + vendor/github.com/gocql/gocql/uuid.go | 272 + .../github.com/golang/protobuf/proto/Makefile | 43 - .../github.com/golang/protobuf/proto/clone.go | 46 +- .../golang/protobuf/proto/decode.go | 668 +- .../golang/protobuf/proto/discard.go | 350 + .../golang/protobuf/proto/encode.go | 1189 +- .../github.com/golang/protobuf/proto/equal.go | 30 +- .../golang/protobuf/proto/extensions.go | 208 +- .../github.com/golang/protobuf/proto/lib.go | 70 +- .../golang/protobuf/proto/message_set.go | 81 +- .../golang/protobuf/proto/pointer_reflect.go | 645 +- .../golang/protobuf/proto/pointer_unsafe.go | 402 +- .../golang/protobuf/proto/properties.go | 422 +- .../golang/protobuf/proto/table_marshal.go | 2681 ++ .../golang/protobuf/proto/table_merge.go | 654 + .../golang/protobuf/proto/table_unmarshal.go | 1967 ++ .../github.com/golang/protobuf/proto/text.go | 61 +- .../golang/protobuf/proto/text_parser.go | 77 +- vendor/github.com/golang/snappy/AUTHORS | 15 + vendor/github.com/golang/snappy/CONTRIBUTORS | 37 + vendor/github.com/golang/snappy/LICENSE | 27 + vendor/github.com/golang/snappy/README | 107 + vendor/github.com/golang/snappy/decode.go | 237 + .../github.com/golang/snappy/decode_amd64.go | 14 + .../github.com/golang/snappy/decode_amd64.s | 490 + .../github.com/golang/snappy/decode_other.go | 101 + vendor/github.com/golang/snappy/encode.go | 285 + .../github.com/golang/snappy/encode_amd64.go | 29 + .../github.com/golang/snappy/encode_amd64.s | 730 + .../github.com/golang/snappy/encode_other.go | 238 + vendor/github.com/golang/snappy/snappy.go | 98 + .../github.com/hailocab/go-hostpool/LICENSE | 21 + .../github.com/hailocab/go-hostpool/README.md | 17 + .../hailocab/go-hostpool/epsilon_greedy.go | 220 + .../go-hostpool/epsilon_value_calculators.go | 40 + .../hailocab/go-hostpool/host_entry.go | 62 + .../hailocab/go-hostpool/hostpool.go | 243 + vendor/github.com/hashicorp/go-hclog/LICENSE | 21 + .../github.com/hashicorp/go-hclog/README.md | 133 + .../github.com/hashicorp/go-hclog/global.go | 34 + vendor/github.com/hashicorp/go-hclog/int.go | 420 + vendor/github.com/hashicorp/go-hclog/log.go | 157 + .../hashicorp/go-hclog/nulllogger.go | 45 + .../hashicorp/go-hclog/stacktrace.go | 108 + .../github.com/hashicorp/go-hclog/stdlog.go | 62 + vendor/github.com/hashicorp/go-plugin/LICENSE | 353 + .../github.com/hashicorp/go-plugin/README.md | 168 + .../github.com/hashicorp/go-plugin/client.go | 792 + .../hashicorp/go-plugin/discover.go | 28 + .../github.com/hashicorp/go-plugin/error.go | 24 + .../hashicorp/go-plugin/grpc_broker.go | 455 + .../hashicorp/go-plugin/grpc_broker.pb.go | 190 + .../hashicorp/go-plugin/grpc_broker.proto | 14 + .../hashicorp/go-plugin/grpc_client.go | 107 + .../hashicorp/go-plugin/grpc_server.go | 132 + .../hashicorp/go-plugin/log_entry.go | 73 + .../hashicorp/go-plugin/mux_broker.go | 204 + .../github.com/hashicorp/go-plugin/plugin.go | 58 + .../github.com/hashicorp/go-plugin/process.go | 24 + .../hashicorp/go-plugin/process_posix.go | 19 + .../hashicorp/go-plugin/process_windows.go | 29 + .../hashicorp/go-plugin/protocol.go | 45 + .../hashicorp/go-plugin/rpc_client.go | 170 + .../hashicorp/go-plugin/rpc_server.go | 197 + .../github.com/hashicorp/go-plugin/server.go | 317 + .../hashicorp/go-plugin/server_mux.go | 31 + .../github.com/hashicorp/go-plugin/stream.go | 18 + .../github.com/hashicorp/go-plugin/testing.go | 175 + .../hashicorp/go-retryablehttp/README.md | 13 +- .../hashicorp/go-retryablehttp/client.go | 244 +- vendor/github.com/hashicorp/vault/LICENSE | 363 + vendor/github.com/hashicorp/vault/api/auth.go | 11 + .../hashicorp/vault/api/auth_token.go | 243 + .../github.com/hashicorp/vault/api/client.go | 724 + vendor/github.com/hashicorp/vault/api/help.go | 25 + .../github.com/hashicorp/vault/api/logical.go | 242 + .../github.com/hashicorp/vault/api/renewer.go | 349 + .../github.com/hashicorp/vault/api/request.go | 145 + .../hashicorp/vault/api/response.go | 77 + .../github.com/hashicorp/vault/api/secret.go | 308 + vendor/github.com/hashicorp/vault/api/ssh.go | 55 + .../hashicorp/vault/api/ssh_agent.go | 231 + vendor/github.com/hashicorp/vault/api/sys.go | 11 + .../hashicorp/vault/api/sys_audit.go | 125 + .../hashicorp/vault/api/sys_auth.go | 119 + .../hashicorp/vault/api/sys_capabilities.go | 49 + .../hashicorp/vault/api/sys_config_cors.go | 56 + .../hashicorp/vault/api/sys_generate_root.go | 110 + .../hashicorp/vault/api/sys_health.go | 33 + .../hashicorp/vault/api/sys_init.go | 54 + .../hashicorp/vault/api/sys_leader.go | 21 + .../hashicorp/vault/api/sys_leases.go | 48 + .../hashicorp/vault/api/sys_mounts.go | 159 + .../hashicorp/vault/api/sys_plugins.go | 117 + .../hashicorp/vault/api/sys_policy.go | 97 + .../hashicorp/vault/api/sys_rekey.go | 309 + .../hashicorp/vault/api/sys_rotate.go | 30 + .../hashicorp/vault/api/sys_seal.go | 62 + .../hashicorp/vault/api/sys_stepdown.go | 10 + .../github.com/hashicorp/vault/audit/audit.go | 63 + .../hashicorp/vault/audit/format.go | 454 + .../hashicorp/vault/audit/format_json.go | 53 + .../hashicorp/vault/audit/format_jsonx.go | 74 + .../hashicorp/vault/audit/formatter.go | 24 + .../hashicorp/vault/audit/hashstructure.go | 319 + .../logical/database/dbplugin/client.go | 75 + .../logical/database/dbplugin/database.pb.go | 1022 + .../logical/database/dbplugin/database.proto | 93 + .../database/dbplugin/databasemiddleware.go | 275 + .../database/dbplugin/grpc_transport.go | 285 + .../database/dbplugin/netrpc_transport.go | 197 + .../logical/database/dbplugin/plugin.go | 148 + .../logical/database/dbplugin/server.go | 39 + .../vault/builtin/logical/pki/backend.go | 108 + .../vault/builtin/logical/pki/ca_util.go | 58 + .../vault/builtin/logical/pki/cert_util.go | 1691 ++ .../vault/builtin/logical/pki/crl_util.go | 205 + .../vault/builtin/logical/pki/fields.go | 232 + .../builtin/logical/pki/path_config_ca.go | 135 + .../builtin/logical/pki/path_config_crl.go | 102 + .../builtin/logical/pki/path_config_urls.go | 162 + .../vault/builtin/logical/pki/path_fetch.go | 276 + .../builtin/logical/pki/path_intermediate.go | 254 + .../builtin/logical/pki/path_issue_sign.go | 364 + .../vault/builtin/logical/pki/path_revoke.go | 96 + .../vault/builtin/logical/pki/path_roles.go | 745 + .../vault/builtin/logical/pki/path_root.go | 485 + .../vault/builtin/logical/pki/path_tidy.go | 219 + .../vault/builtin/logical/pki/secret_certs.go | 52 + .../vault/builtin/logical/pki/util.go | 7 + .../vault/helper/builtinplugins/builtin.go | 50 + .../vault/helper/certutil/helpers.go | 275 + .../hashicorp/vault/helper/certutil/types.go | 595 + .../vault/helper/compressutil/compress.go | 192 + .../hashicorp/vault/helper/consts/consts.go | 7 + .../hashicorp/vault/helper/consts/error.go | 16 + .../vault/helper/consts/replication.go | 82 + .../hashicorp/vault/helper/dbtxn/dbtxn.go | 63 + .../hashicorp/vault/helper/errutil/error.go | 20 + .../vault/helper/forwarding/types.pb.go | 343 + .../vault/helper/forwarding/types.proto | 48 + .../hashicorp/vault/helper/forwarding/util.go | 203 + .../hashicorp/vault/helper/hclutil/hcl.go | 36 + .../vault/helper/identity/identity.go | 65 + .../vault/helper/identity/sentinel.go | 125 + .../vault/helper/identity/types.pb.go | 505 + .../vault/helper/identity/types.proto | 166 + .../hashicorp/vault/helper/jsonutil/json.go | 100 + .../hashicorp/vault/helper/kdf/kdf.go | 77 + .../helper/keysutil/encrypted_key_storage.go | 288 + .../vault/helper/keysutil/lock_manager.go | 407 + .../hashicorp/vault/helper/keysutil/policy.go | 1463 + .../hashicorp/vault/helper/locksutil/locks.go | 60 + .../hashicorp/vault/helper/logging/vault.go | 39 + .../hashicorp/vault/helper/mlock/mlock.go | 15 + .../vault/helper/mlock/mlock_unavail.go | 13 + .../vault/helper/mlock/mlock_unix.go | 18 + .../vault/helper/parseutil/parseutil.go | 163 + .../vault/helper/pathmanager/pathmanager.go | 136 + .../vault/helper/pgpkeys/encrypt_decrypt.go | 118 + .../hashicorp/vault/helper/pgpkeys/flag.go | 140 + .../hashicorp/vault/helper/pgpkeys/keybase.go | 117 + .../vault/helper/pgpkeys/test_keys.go | 271 + .../hashicorp/vault/helper/pluginutil/env.go | 66 + .../vault/helper/pluginutil/runner.go | 182 + .../hashicorp/vault/helper/pluginutil/tls.go | 241 + .../vault/helper/policyutil/policyutil.go | 128 + .../hashicorp/vault/helper/reload/reload.go | 85 + .../hashicorp/vault/helper/salt/salt.go | 178 + .../helper/storagepacker/storagepacker.go | 355 + .../vault/helper/storagepacker/types.pb.go | 139 + .../vault/helper/storagepacker/types.proto | 17 + .../hashicorp/vault/helper/strutil/strutil.go | 327 + .../hashicorp/vault/helper/tlsutil/tlsutil.go | 54 + .../vault/helper/wrapping/wrapinfo.go | 37 + .../hashicorp/vault/helper/xor/xor.go | 48 + .../github.com/hashicorp/vault/http/cors.go | 67 + .../hashicorp/vault/http/handler.go | 577 + .../github.com/hashicorp/vault/http/help.go | 47 + .../hashicorp/vault/http/logical.go | 317 + .../hashicorp/vault/http/stub_assets.go | 16 + .../hashicorp/vault/http/sys_generate_root.go | 192 + .../hashicorp/vault/http/sys_health.go | 183 + .../hashicorp/vault/http/sys_init.go | 165 + .../hashicorp/vault/http/sys_leader.go | 46 + .../hashicorp/vault/http/sys_rekey.go | 411 + .../hashicorp/vault/http/sys_seal.go | 235 + .../hashicorp/vault/http/testing.go | 56 + .../hashicorp/vault/logical/auth.go | 92 + .../hashicorp/vault/logical/connection.go | 15 + .../hashicorp/vault/logical/error.go | 50 + .../vault/logical/framework/backend.go | 583 + .../vault/logical/framework/field_data.go | 294 + .../vault/logical/framework/field_type.go | 70 + .../vault/logical/framework/lease.go | 106 + .../hashicorp/vault/logical/framework/path.go | 163 + .../vault/logical/framework/path_map.go | 283 + .../vault/logical/framework/path_struct.go | 124 + .../vault/logical/framework/policy_map.go | 65 + .../vault/logical/framework/secret.go | 91 + .../vault/logical/framework/template.go | 42 + .../vault/logical/framework/testing.go | 15 + .../hashicorp/vault/logical/framework/wal.go | 101 + .../hashicorp/vault/logical/identity.pb.go | 159 + .../hashicorp/vault/logical/identity.proto | 29 + .../hashicorp/vault/logical/lease.go | 53 + .../hashicorp/vault/logical/logical.go | 126 + .../hashicorp/vault/logical/request.go | 295 + .../hashicorp/vault/logical/response.go | 162 + .../hashicorp/vault/logical/response_util.go | 136 + .../hashicorp/vault/logical/secret.go | 30 + .../hashicorp/vault/logical/storage.go | 121 + .../hashicorp/vault/logical/storage_inmem.go | 67 + .../hashicorp/vault/logical/system_view.go | 121 + .../hashicorp/vault/logical/testing.go | 84 + .../hashicorp/vault/logical/token.go | 119 + .../vault/logical/translate_response.go | 149 + .../hashicorp/vault/physical/cache.go | 220 + .../hashicorp/vault/physical/inmem/inmem.go | 224 + .../vault/physical/inmem/inmem_ha.go | 167 + .../hashicorp/vault/physical/latency.go | 95 + .../hashicorp/vault/physical/physical.go | 158 + .../vault/physical/physical_access.go | 38 + .../hashicorp/vault/physical/physical_view.go | 98 + .../hashicorp/vault/physical/testing.go | 488 + .../hashicorp/vault/physical/transactions.go | 126 + .../hashicorp/vault/physical/types.pb.go | 102 + .../hashicorp/vault/physical/types.proto | 15 + .../plugins/database/cassandra/cassandra.go | 242 + .../database/cassandra/connection_producer.go | 255 + .../vault/plugins/database/hana/hana.go | 296 + .../database/mongodb/connection_producer.go | 228 + .../vault/plugins/database/mongodb/mongodb.go | 224 + .../vault/plugins/database/mongodb/util.go | 39 + .../vault/plugins/database/mssql/mssql.go | 391 + .../vault/plugins/database/mysql/mysql.go | 317 + .../plugins/database/postgresql/postgresql.go | 427 + .../helper/database/connutil/connutil.go | 25 + .../plugins/helper/database/connutil/sql.go | 164 + .../helper/database/credsutil/credsutil.go | 49 + .../plugins/helper/database/credsutil/sql.go | 72 + .../plugins/helper/database/dbutil/dbutil.go | 52 + .../hashicorp/vault/plugins/serve.go | 31 + .../hashicorp/vault/shamir/shamir.go | 262 + .../hashicorp/vault/shamir/tables.go | 77 + .../github.com/hashicorp/vault/vault/acl.go | 460 + .../github.com/hashicorp/vault/vault/audit.go | 461 + .../hashicorp/vault/vault/audit_broker.go | 200 + .../hashicorp/vault/vault/audited_headers.go | 162 + .../github.com/hashicorp/vault/vault/auth.go | 625 + .../hashicorp/vault/vault/barrier.go | 183 + .../hashicorp/vault/vault/barrier_access.go | 24 + .../hashicorp/vault/vault/barrier_aes_gcm.go | 900 + .../hashicorp/vault/vault/barrier_view.go | 145 + .../hashicorp/vault/vault/capabilities.go | 75 + .../hashicorp/vault/vault/cluster.go | 458 + .../github.com/hashicorp/vault/vault/core.go | 1437 + .../github.com/hashicorp/vault/vault/cors.go | 161 + .../vault/vault/dynamic_system_view.go | 190 + .../hashicorp/vault/vault/expiration.go | 1422 + .../hashicorp/vault/vault/generate_root.go | 366 + vendor/github.com/hashicorp/vault/vault/ha.go | 737 + .../hashicorp/vault/vault/identity_lookup.go | 329 + .../hashicorp/vault/vault/identity_store.go | 399 + .../vault/vault/identity_store_aliases.go | 480 + .../vault/vault/identity_store_entities.go | 599 + .../vault/identity_store_group_aliases.go | 327 + .../vault/vault/identity_store_groups.go | 399 + .../vault/vault/identity_store_schema.go | 217 + .../vault/vault/identity_store_structs.go | 81 + .../vault/vault/identity_store_upgrade.go | 184 + .../vault/vault/identity_store_util.go | 2415 ++ .../github.com/hashicorp/vault/vault/init.go | 305 + .../hashicorp/vault/vault/keyring.go | 203 + .../vault/vault/logical_cubbyhole.go | 207 + .../vault/vault/logical_passthrough.go | 247 + .../hashicorp/vault/vault/logical_system.go | 4326 +++ .../vault/vault/logical_system_helpers.go | 54 + .../github.com/hashicorp/vault/vault/mount.go | 1111 + .../hashicorp/vault/vault/plugin_catalog.go | 189 + .../hashicorp/vault/vault/plugin_reload.go | 143 + .../hashicorp/vault/vault/policy.go | 308 + .../hashicorp/vault/vault/policy_store.go | 519 + .../github.com/hashicorp/vault/vault/rekey.go | 968 + .../vault/vault/request_forwarding.go | 516 + .../vault/request_forwarding_service.pb.go | 274 + .../vault/request_forwarding_service.proto | 28 + .../hashicorp/vault/vault/request_handling.go | 868 + .../hashicorp/vault/vault/rollback.go | 244 + .../hashicorp/vault/vault/router.go | 655 + .../hashicorp/vault/vault/router_access.go | 14 + .../github.com/hashicorp/vault/vault/seal.go | 383 + .../hashicorp/vault/vault/seal_access.go | 63 + .../hashicorp/vault/vault/seal_testing.go | 88 + .../hashicorp/vault/vault/sealunwrapper.go | 183 + .../hashicorp/vault/vault/testing.go | 1435 + .../hashicorp/vault/vault/token_store.go | 2616 ++ vendor/github.com/hashicorp/vault/vault/ui.go | 217 + .../github.com/hashicorp/vault/vault/util.go | 42 + .../hashicorp/vault/vault/wrapping.go | 348 + .../github.com/hashicorp/vault/version/cgo.go | 7 + .../hashicorp/vault/version/version.go | 87 + .../hashicorp/vault/version/version_base.go | 11 + vendor/github.com/jefferai/jsonx/LICENSE | 373 + vendor/github.com/jefferai/jsonx/README.md | 12 + vendor/github.com/jefferai/jsonx/jsonx.go | 132 + vendor/github.com/keybase/go-crypto/LICENSE | 27 + vendor/github.com/keybase/go-crypto/PATENTS | 22 + .../keybase/go-crypto/brainpool/brainpool.go | 134 + .../keybase/go-crypto/brainpool/rcurve.go | 83 + .../keybase/go-crypto/cast5/cast5.go | 526 + .../go-crypto/curve25519/const_amd64.s | 20 + .../go-crypto/curve25519/cswap_amd64.s | 88 + .../go-crypto/curve25519/curve25519.go | 841 + .../go-crypto/curve25519/curve_impl.go | 113 + .../keybase/go-crypto/curve25519/doc.go | 23 + .../go-crypto/curve25519/freeze_amd64.s | 94 + .../go-crypto/curve25519/ladderstep_amd64.s | 1398 + .../go-crypto/curve25519/mont25519_amd64.go | 240 + .../keybase/go-crypto/curve25519/mul_amd64.s | 191 + .../go-crypto/curve25519/square_amd64.s | 153 + .../keybase/go-crypto/ed25519/ed25519.go | 188 + .../ed25519/internal/edwards25519/const.go | 1422 + .../internal/edwards25519/edwards25519.go | 1793 ++ .../keybase/go-crypto/openpgp/armor/armor.go | 253 + .../keybase/go-crypto/openpgp/armor/encode.go | 160 + .../go-crypto/openpgp/canonical_text.go | 59 + .../keybase/go-crypto/openpgp/ecdh/ecdh.go | 282 + .../go-crypto/openpgp/elgamal/elgamal.go | 122 + .../go-crypto/openpgp/errors/errors.go | 80 + .../keybase/go-crypto/openpgp/keys.go | 911 + .../go-crypto/openpgp/packet/compressed.go | 124 + .../go-crypto/openpgp/packet/config.go | 98 + .../keybase/go-crypto/openpgp/packet/ecdh.go | 104 + .../go-crypto/openpgp/packet/encrypted_key.go | 226 + .../go-crypto/openpgp/packet/literal.go | 89 + .../keybase/go-crypto/openpgp/packet/ocfb.go | 143 + .../openpgp/packet/one_pass_signature.go | 74 + .../go-crypto/openpgp/packet/opaque.go | 162 + .../go-crypto/openpgp/packet/packet.go | 565 + .../go-crypto/openpgp/packet/private_key.go | 550 + .../go-crypto/openpgp/packet/public_key.go | 947 + .../go-crypto/openpgp/packet/public_key_v3.go | 280 + .../go-crypto/openpgp/packet/reader.go | 76 + .../go-crypto/openpgp/packet/signature.go | 882 + .../go-crypto/openpgp/packet/signature_v3.go | 146 + .../openpgp/packet/symmetric_key_encrypted.go | 158 + .../openpgp/packet/symmetrically_encrypted.go | 291 + .../go-crypto/openpgp/packet/userattribute.go | 91 + .../go-crypto/openpgp/packet/userid.go | 160 + .../keybase/go-crypto/openpgp/patch.sh | 7 + .../keybase/go-crypto/openpgp/read.go | 500 + .../keybase/go-crypto/openpgp/s2k/s2k.go | 326 + .../keybase/go-crypto/openpgp/sig-v3.patch | 135 + .../keybase/go-crypto/openpgp/write.go | 506 + .../keybase/go-crypto/rsa/pkcs1v15.go | 325 + .../github.com/keybase/go-crypto/rsa/pss.go | 297 + .../github.com/keybase/go-crypto/rsa/rsa.go | 646 + vendor/github.com/lib/pq/CONTRIBUTING.md | 29 + vendor/github.com/lib/pq/LICENSE.md | 8 + vendor/github.com/lib/pq/README.md | 95 + vendor/github.com/lib/pq/TESTS.md | 33 + vendor/github.com/lib/pq/array.go | 756 + vendor/github.com/lib/pq/buf.go | 91 + vendor/github.com/lib/pq/conn.go | 1854 ++ vendor/github.com/lib/pq/conn_go18.go | 131 + vendor/github.com/lib/pq/connector.go | 43 + vendor/github.com/lib/pq/copy.go | 282 + vendor/github.com/lib/pq/doc.go | 245 + vendor/github.com/lib/pq/encode.go | 603 + vendor/github.com/lib/pq/error.go | 515 + vendor/github.com/lib/pq/notify.go | 794 + vendor/github.com/lib/pq/oid/doc.go | 6 + vendor/github.com/lib/pq/oid/types.go | 343 + vendor/github.com/lib/pq/rows.go | 93 + vendor/github.com/lib/pq/ssl.go | 169 + vendor/github.com/lib/pq/ssl_go1.7.go | 14 + vendor/github.com/lib/pq/ssl_permissions.go | 20 + vendor/github.com/lib/pq/ssl_renegotiation.go | 8 + vendor/github.com/lib/pq/ssl_windows.go | 9 + vendor/github.com/lib/pq/url.go | 76 + vendor/github.com/lib/pq/user_posix.go | 24 + vendor/github.com/lib/pq/user_windows.go | 27 + vendor/github.com/lib/pq/uuid.go | 23 + .../mitchellh/reflectwalk/location.go | 2 + .../mitchellh/reflectwalk/location_string.go | 8 +- .../mitchellh/reflectwalk/reflectwalk.go | 184 +- vendor/github.com/oklog/run/LICENSE | 201 + vendor/github.com/oklog/run/README.md | 75 + vendor/github.com/oklog/run/group.go | 62 + .../patrickmn/go-cache/CONTRIBUTORS | 9 + vendor/github.com/patrickmn/go-cache/LICENSE | 19 + .../github.com/patrickmn/go-cache/README.md | 83 + vendor/github.com/patrickmn/go-cache/cache.go | 1161 + .../github.com/patrickmn/go-cache/sharded.go | 192 + vendor/github.com/ryanuber/go-glob/LICENSE | 21 + vendor/github.com/ryanuber/go-glob/README.md | 29 + vendor/github.com/ryanuber/go-glob/glob.go | 56 + .../chacha20poly1305/chacha20poly1305.go | 91 + .../chacha20poly1305_amd64.go | 87 + .../chacha20poly1305/chacha20poly1305_amd64.s | 2695 ++ .../chacha20poly1305_generic.go | 81 + .../chacha20poly1305_noasm.go | 15 + vendor/golang.org/x/crypto/cryptobyte/asn1.go | 751 + .../x/crypto/cryptobyte/asn1/asn1.go | 46 + .../golang.org/x/crypto/cryptobyte/builder.go | 309 + .../golang.org/x/crypto/cryptobyte/string.go | 166 + vendor/golang.org/x/crypto/hkdf/hkdf.go | 75 + .../x/crypto/internal/subtle/aliasing.go | 32 + vendor/golang.org/x/crypto/md4/md4.go | 118 + vendor/golang.org/x/crypto/md4/md4block.go | 89 + vendor/golang.org/x/net/context/context.go | 114 +- vendor/golang.org/x/net/context/go17.go | 4 +- vendor/golang.org/x/net/context/go19.go | 20 + vendor/golang.org/x/net/context/pre_go17.go | 18 +- vendor/golang.org/x/net/context/pre_go19.go | 109 + vendor/golang.org/x/sys/cpu/cpu.go | 38 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 7 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 7 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 16 + vendor/golang.org/x/sys/cpu/cpu_gccgo.c | 43 + vendor/golang.org/x/sys/cpu/cpu_gccgo.go | 26 + vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 9 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 9 + vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 9 + vendor/golang.org/x/sys/cpu/cpu_s390x.go | 7 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 55 + vendor/golang.org/x/sys/cpu/cpu_x86.s | 27 + vendor/gopkg.in/inf.v0/LICENSE | 28 + vendor/gopkg.in/inf.v0/dec.go | 615 + vendor/gopkg.in/inf.v0/rounder.go | 145 + vendor/gopkg.in/mgo.v2/LICENSE | 25 + vendor/gopkg.in/mgo.v2/Makefile | 5 + vendor/gopkg.in/mgo.v2/README.md | 4 + vendor/gopkg.in/mgo.v2/auth.go | 467 + vendor/gopkg.in/mgo.v2/bson/LICENSE | 25 + vendor/gopkg.in/mgo.v2/bson/bson.go | 738 + vendor/gopkg.in/mgo.v2/bson/decimal.go | 310 + vendor/gopkg.in/mgo.v2/bson/decode.go | 849 + vendor/gopkg.in/mgo.v2/bson/encode.go | 514 + vendor/gopkg.in/mgo.v2/bson/json.go | 380 + vendor/gopkg.in/mgo.v2/bulk.go | 351 + vendor/gopkg.in/mgo.v2/cluster.go | 682 + vendor/gopkg.in/mgo.v2/doc.go | 31 + vendor/gopkg.in/mgo.v2/gridfs.go | 761 + vendor/gopkg.in/mgo.v2/internal/json/LICENSE | 27 + .../gopkg.in/mgo.v2/internal/json/decode.go | 1685 ++ .../gopkg.in/mgo.v2/internal/json/encode.go | 1256 + .../mgo.v2/internal/json/extension.go | 95 + vendor/gopkg.in/mgo.v2/internal/json/fold.go | 143 + .../gopkg.in/mgo.v2/internal/json/indent.go | 141 + .../gopkg.in/mgo.v2/internal/json/scanner.go | 697 + .../gopkg.in/mgo.v2/internal/json/stream.go | 510 + vendor/gopkg.in/mgo.v2/internal/json/tags.go | 44 + vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c | 77 + vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go | 138 + .../mgo.v2/internal/sasl/sasl_windows.c | 122 + .../mgo.v2/internal/sasl/sasl_windows.go | 142 + .../mgo.v2/internal/sasl/sasl_windows.h | 7 + .../mgo.v2/internal/sasl/sspi_windows.c | 96 + .../mgo.v2/internal/sasl/sspi_windows.h | 70 + .../gopkg.in/mgo.v2/internal/scram/scram.go | 266 + vendor/gopkg.in/mgo.v2/log.go | 133 + vendor/gopkg.in/mgo.v2/queue.go | 91 + vendor/gopkg.in/mgo.v2/raceoff.go | 5 + vendor/gopkg.in/mgo.v2/raceon.go | 5 + vendor/gopkg.in/mgo.v2/saslimpl.go | 11 + vendor/gopkg.in/mgo.v2/saslstub.go | 11 + vendor/gopkg.in/mgo.v2/server.go | 463 + vendor/gopkg.in/mgo.v2/session.go | 4825 ++++ vendor/gopkg.in/mgo.v2/socket.go | 707 + vendor/gopkg.in/mgo.v2/stats.go | 147 + vendor/vendor.json | 122 +- 704 files changed, 235144 insertions(+), 3251 deletions(-) create mode 100644 vendor/cloud.google.com/go/civil/civil.go create mode 100644 vendor/github.com/Jeffail/gabs/LICENSE create mode 100644 vendor/github.com/Jeffail/gabs/README.md create mode 100644 vendor/github.com/Jeffail/gabs/gabs.go create mode 100644 vendor/github.com/Jeffail/gabs/gabs_logo.png create mode 100644 vendor/github.com/SAP/go-hdb/LICENSE create mode 100644 vendor/github.com/SAP/go-hdb/NOTICE create mode 100644 vendor/github.com/SAP/go-hdb/driver/bytes.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/connector.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/converter.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/decimal.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/doc.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/driver.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/driver_future.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/driver_go1.10.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/driver_legacy.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/dsn.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/error.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/identifier.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/lob.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/sqltrace/doc.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/sqltrace/sqltrace.go create mode 100644 vendor/github.com/SAP/go-hdb/driver/time.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/bufio/bufio.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/clientid.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/command.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/connectoption.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/connectoption_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/connectoptions.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/datatype.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/datatype_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/doc.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/endianess.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/endianess_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/error.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/errorlevel.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/fetchsize.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/field.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/functioncode.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/functioncode_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/init.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/littleendian.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/lob.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/message.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/messagetype.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/messagetype_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/option.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/parameter.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/part.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/partkind.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/partkind_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/querytype.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/querytype_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/result.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/rowsaffected.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/scramsha256.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/segment.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/segmentkind_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/session.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/sniffer.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/statementcontext.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/statementcontexttype_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/statementid.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/tableresult.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/time.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/topology.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/topologyoption_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/transactionflags.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/transactionflagtype_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/typecode.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/protocol/typecode_string.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/unicode/cesu8/cesu8.go create mode 100644 vendor/github.com/SAP/go-hdb/internal/unicode/unicode.go create mode 100644 vendor/github.com/SermoDigital/jose/LICENSE create mode 100644 vendor/github.com/SermoDigital/jose/README.md create mode 100755 vendor/github.com/SermoDigital/jose/_test.sh create mode 100644 vendor/github.com/SermoDigital/jose/base64.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/doc.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/ecdsa.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/ecdsa_utils.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/errors.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/hmac.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/none.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/rsa.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/rsa_pss.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/rsa_utils.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/signature.go create mode 100644 vendor/github.com/SermoDigital/jose/crypto/signing_method.go create mode 100644 vendor/github.com/SermoDigital/jose/doc.go create mode 100644 vendor/github.com/SermoDigital/jose/header.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/claims.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/doc.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/errors.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/jws.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/jws_serialize.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/jws_validate.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/jwt.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/payload.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/rawbase64.go create mode 100644 vendor/github.com/SermoDigital/jose/jws/signing_methods.go create mode 100644 vendor/github.com/SermoDigital/jose/jwt/claims.go create mode 100644 vendor/github.com/SermoDigital/jose/jwt/doc.go create mode 100644 vendor/github.com/SermoDigital/jose/jwt/eq.go create mode 100644 vendor/github.com/SermoDigital/jose/jwt/errors.go create mode 100644 vendor/github.com/SermoDigital/jose/jwt/jwt.go create mode 100644 vendor/github.com/SermoDigital/jose/time.go create mode 100644 vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md create mode 100644 vendor/github.com/asaskevich/govalidator/LICENSE create mode 100644 vendor/github.com/asaskevich/govalidator/README.md create mode 100644 vendor/github.com/asaskevich/govalidator/arrays.go create mode 100644 vendor/github.com/asaskevich/govalidator/converter.go create mode 100644 vendor/github.com/asaskevich/govalidator/error.go create mode 100644 vendor/github.com/asaskevich/govalidator/numerics.go create mode 100644 vendor/github.com/asaskevich/govalidator/patterns.go create mode 100644 vendor/github.com/asaskevich/govalidator/types.go create mode 100644 vendor/github.com/asaskevich/govalidator/utils.go create mode 100644 vendor/github.com/asaskevich/govalidator/validator.go create mode 100644 vendor/github.com/asaskevich/govalidator/wercker.yml create mode 100644 vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt create mode 100644 vendor/github.com/denisenkom/go-mssqldb/README.md create mode 100644 vendor/github.com/denisenkom/go-mssqldb/appveyor.yml create mode 100644 vendor/github.com/denisenkom/go-mssqldb/buf.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/decimal.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/doc.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/error.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/log.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/net.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/ntlm.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/parser.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/rpc.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/tds.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/token.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/token_string.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/tran.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/types.go create mode 100644 vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go create mode 100644 vendor/github.com/fatih/structs/LICENSE create mode 100644 vendor/github.com/fatih/structs/README.md create mode 100644 vendor/github.com/fatih/structs/field.go create mode 100644 vendor/github.com/fatih/structs/structs.go create mode 100644 vendor/github.com/fatih/structs/tags.go create mode 100644 vendor/github.com/go-sql-driver/mysql/AUTHORS create mode 100644 vendor/github.com/go-sql-driver/mysql/CHANGELOG.md create mode 100644 vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md create mode 100644 vendor/github.com/go-sql-driver/mysql/LICENSE create mode 100644 vendor/github.com/go-sql-driver/mysql/README.md create mode 100644 vendor/github.com/go-sql-driver/mysql/auth.go create mode 100644 vendor/github.com/go-sql-driver/mysql/buffer.go create mode 100644 vendor/github.com/go-sql-driver/mysql/collations.go create mode 100644 vendor/github.com/go-sql-driver/mysql/connection.go create mode 100644 vendor/github.com/go-sql-driver/mysql/const.go create mode 100644 vendor/github.com/go-sql-driver/mysql/driver.go create mode 100644 vendor/github.com/go-sql-driver/mysql/dsn.go create mode 100644 vendor/github.com/go-sql-driver/mysql/errors.go create mode 100644 vendor/github.com/go-sql-driver/mysql/fields.go create mode 100644 vendor/github.com/go-sql-driver/mysql/infile.go create mode 100644 vendor/github.com/go-sql-driver/mysql/packets.go create mode 100644 vendor/github.com/go-sql-driver/mysql/result.go create mode 100644 vendor/github.com/go-sql-driver/mysql/rows.go create mode 100644 vendor/github.com/go-sql-driver/mysql/statement.go create mode 100644 vendor/github.com/go-sql-driver/mysql/transaction.go create mode 100644 vendor/github.com/go-sql-driver/mysql/utils.go create mode 100644 vendor/github.com/gocql/gocql/AUTHORS create mode 100644 vendor/github.com/gocql/gocql/CONTRIBUTING.md create mode 100644 vendor/github.com/gocql/gocql/LICENSE create mode 100644 vendor/github.com/gocql/gocql/README.md create mode 100644 vendor/github.com/gocql/gocql/address_translators.go create mode 100644 vendor/github.com/gocql/gocql/cluster.go create mode 100644 vendor/github.com/gocql/gocql/compressor.go create mode 100644 vendor/github.com/gocql/gocql/conn.go create mode 100644 vendor/github.com/gocql/gocql/connectionpool.go create mode 100644 vendor/github.com/gocql/gocql/control.go create mode 100644 vendor/github.com/gocql/gocql/debug_off.go create mode 100644 vendor/github.com/gocql/gocql/debug_on.go create mode 100644 vendor/github.com/gocql/gocql/doc.go create mode 100644 vendor/github.com/gocql/gocql/errors.go create mode 100644 vendor/github.com/gocql/gocql/events.go create mode 100644 vendor/github.com/gocql/gocql/filters.go create mode 100644 vendor/github.com/gocql/gocql/frame.go create mode 100644 vendor/github.com/gocql/gocql/fuzz.go create mode 100644 vendor/github.com/gocql/gocql/go.mod create mode 100644 vendor/github.com/gocql/gocql/go.modverify create mode 100644 vendor/github.com/gocql/gocql/helpers.go create mode 100644 vendor/github.com/gocql/gocql/host_source.go create mode 100644 vendor/github.com/gocql/gocql/host_source_gen.go create mode 100755 vendor/github.com/gocql/gocql/install_test_deps.sh create mode 100755 vendor/github.com/gocql/gocql/integration.sh create mode 100644 vendor/github.com/gocql/gocql/internal/lru/lru.go create mode 100644 vendor/github.com/gocql/gocql/internal/murmur/murmur.go create mode 100644 vendor/github.com/gocql/gocql/internal/murmur/murmur_unsafe.go create mode 100644 vendor/github.com/gocql/gocql/internal/streams/streams.go create mode 100644 vendor/github.com/gocql/gocql/logger.go create mode 100644 vendor/github.com/gocql/gocql/marshal.go create mode 100644 vendor/github.com/gocql/gocql/metadata.go create mode 100644 vendor/github.com/gocql/gocql/policies.go create mode 100644 vendor/github.com/gocql/gocql/prepared_cache.go create mode 100644 vendor/github.com/gocql/gocql/query_executor.go create mode 100644 vendor/github.com/gocql/gocql/ring.go create mode 100644 vendor/github.com/gocql/gocql/session.go create mode 100644 vendor/github.com/gocql/gocql/token.go create mode 100644 vendor/github.com/gocql/gocql/topology.go create mode 100644 vendor/github.com/gocql/gocql/uuid.go delete mode 100644 vendor/github.com/golang/protobuf/proto/Makefile create mode 100644 vendor/github.com/golang/protobuf/proto/discard.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_marshal.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_merge.go create mode 100644 vendor/github.com/golang/protobuf/proto/table_unmarshal.go create mode 100644 vendor/github.com/golang/snappy/AUTHORS create mode 100644 vendor/github.com/golang/snappy/CONTRIBUTORS create mode 100644 vendor/github.com/golang/snappy/LICENSE create mode 100644 vendor/github.com/golang/snappy/README create mode 100644 vendor/github.com/golang/snappy/decode.go create mode 100644 vendor/github.com/golang/snappy/decode_amd64.go create mode 100644 vendor/github.com/golang/snappy/decode_amd64.s create mode 100644 vendor/github.com/golang/snappy/decode_other.go create mode 100644 vendor/github.com/golang/snappy/encode.go create mode 100644 vendor/github.com/golang/snappy/encode_amd64.go create mode 100644 vendor/github.com/golang/snappy/encode_amd64.s create mode 100644 vendor/github.com/golang/snappy/encode_other.go create mode 100644 vendor/github.com/golang/snappy/snappy.go create mode 100644 vendor/github.com/hailocab/go-hostpool/LICENSE create mode 100644 vendor/github.com/hailocab/go-hostpool/README.md create mode 100644 vendor/github.com/hailocab/go-hostpool/epsilon_greedy.go create mode 100644 vendor/github.com/hailocab/go-hostpool/epsilon_value_calculators.go create mode 100644 vendor/github.com/hailocab/go-hostpool/host_entry.go create mode 100644 vendor/github.com/hailocab/go-hostpool/hostpool.go create mode 100644 vendor/github.com/hashicorp/go-hclog/LICENSE create mode 100644 vendor/github.com/hashicorp/go-hclog/README.md create mode 100644 vendor/github.com/hashicorp/go-hclog/global.go create mode 100644 vendor/github.com/hashicorp/go-hclog/int.go create mode 100644 vendor/github.com/hashicorp/go-hclog/log.go create mode 100644 vendor/github.com/hashicorp/go-hclog/nulllogger.go create mode 100644 vendor/github.com/hashicorp/go-hclog/stacktrace.go create mode 100644 vendor/github.com/hashicorp/go-hclog/stdlog.go create mode 100644 vendor/github.com/hashicorp/go-plugin/LICENSE create mode 100644 vendor/github.com/hashicorp/go-plugin/README.md create mode 100644 vendor/github.com/hashicorp/go-plugin/client.go create mode 100644 vendor/github.com/hashicorp/go-plugin/discover.go create mode 100644 vendor/github.com/hashicorp/go-plugin/error.go create mode 100644 vendor/github.com/hashicorp/go-plugin/grpc_broker.go create mode 100644 vendor/github.com/hashicorp/go-plugin/grpc_broker.pb.go create mode 100644 vendor/github.com/hashicorp/go-plugin/grpc_broker.proto create mode 100644 vendor/github.com/hashicorp/go-plugin/grpc_client.go create mode 100644 vendor/github.com/hashicorp/go-plugin/grpc_server.go create mode 100644 vendor/github.com/hashicorp/go-plugin/log_entry.go create mode 100644 vendor/github.com/hashicorp/go-plugin/mux_broker.go create mode 100644 vendor/github.com/hashicorp/go-plugin/plugin.go create mode 100644 vendor/github.com/hashicorp/go-plugin/process.go create mode 100644 vendor/github.com/hashicorp/go-plugin/process_posix.go create mode 100644 vendor/github.com/hashicorp/go-plugin/process_windows.go create mode 100644 vendor/github.com/hashicorp/go-plugin/protocol.go create mode 100644 vendor/github.com/hashicorp/go-plugin/rpc_client.go create mode 100644 vendor/github.com/hashicorp/go-plugin/rpc_server.go create mode 100644 vendor/github.com/hashicorp/go-plugin/server.go create mode 100644 vendor/github.com/hashicorp/go-plugin/server_mux.go create mode 100644 vendor/github.com/hashicorp/go-plugin/stream.go create mode 100644 vendor/github.com/hashicorp/go-plugin/testing.go create mode 100644 vendor/github.com/hashicorp/vault/LICENSE create mode 100644 vendor/github.com/hashicorp/vault/api/auth.go create mode 100644 vendor/github.com/hashicorp/vault/api/auth_token.go create mode 100644 vendor/github.com/hashicorp/vault/api/client.go create mode 100644 vendor/github.com/hashicorp/vault/api/help.go create mode 100644 vendor/github.com/hashicorp/vault/api/logical.go create mode 100644 vendor/github.com/hashicorp/vault/api/renewer.go create mode 100644 vendor/github.com/hashicorp/vault/api/request.go create mode 100644 vendor/github.com/hashicorp/vault/api/response.go create mode 100644 vendor/github.com/hashicorp/vault/api/secret.go create mode 100644 vendor/github.com/hashicorp/vault/api/ssh.go create mode 100644 vendor/github.com/hashicorp/vault/api/ssh_agent.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_audit.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_auth.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_capabilities.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_config_cors.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_generate_root.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_health.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_init.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_leader.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_leases.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_mounts.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_plugins.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_policy.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_rekey.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_rotate.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_seal.go create mode 100644 vendor/github.com/hashicorp/vault/api/sys_stepdown.go create mode 100644 vendor/github.com/hashicorp/vault/audit/audit.go create mode 100644 vendor/github.com/hashicorp/vault/audit/format.go create mode 100644 vendor/github.com/hashicorp/vault/audit/format_json.go create mode 100644 vendor/github.com/hashicorp/vault/audit/format_jsonx.go create mode 100644 vendor/github.com/hashicorp/vault/audit/formatter.go create mode 100644 vendor/github.com/hashicorp/vault/audit/hashstructure.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/client.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.pb.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/database.proto create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/databasemiddleware.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/grpc_transport.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/netrpc_transport.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/plugin.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/server.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/backend.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/ca_util.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/cert_util.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/crl_util.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/fields.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_ca.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_crl.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_urls.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_fetch.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_intermediate.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_issue_sign.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_revoke.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_roles.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_root.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/path_tidy.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/secret_certs.go create mode 100644 vendor/github.com/hashicorp/vault/builtin/logical/pki/util.go create mode 100644 vendor/github.com/hashicorp/vault/helper/builtinplugins/builtin.go create mode 100644 vendor/github.com/hashicorp/vault/helper/certutil/helpers.go create mode 100644 vendor/github.com/hashicorp/vault/helper/certutil/types.go create mode 100644 vendor/github.com/hashicorp/vault/helper/compressutil/compress.go create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/consts.go create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/error.go create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/replication.go create mode 100644 vendor/github.com/hashicorp/vault/helper/dbtxn/dbtxn.go create mode 100644 vendor/github.com/hashicorp/vault/helper/errutil/error.go create mode 100644 vendor/github.com/hashicorp/vault/helper/forwarding/types.pb.go create mode 100644 vendor/github.com/hashicorp/vault/helper/forwarding/types.proto create mode 100644 vendor/github.com/hashicorp/vault/helper/forwarding/util.go create mode 100644 vendor/github.com/hashicorp/vault/helper/hclutil/hcl.go create mode 100644 vendor/github.com/hashicorp/vault/helper/identity/identity.go create mode 100644 vendor/github.com/hashicorp/vault/helper/identity/sentinel.go create mode 100644 vendor/github.com/hashicorp/vault/helper/identity/types.pb.go create mode 100644 vendor/github.com/hashicorp/vault/helper/identity/types.proto create mode 100644 vendor/github.com/hashicorp/vault/helper/jsonutil/json.go create mode 100644 vendor/github.com/hashicorp/vault/helper/kdf/kdf.go create mode 100644 vendor/github.com/hashicorp/vault/helper/keysutil/encrypted_key_storage.go create mode 100644 vendor/github.com/hashicorp/vault/helper/keysutil/lock_manager.go create mode 100644 vendor/github.com/hashicorp/vault/helper/keysutil/policy.go create mode 100644 vendor/github.com/hashicorp/vault/helper/locksutil/locks.go create mode 100644 vendor/github.com/hashicorp/vault/helper/logging/vault.go create mode 100644 vendor/github.com/hashicorp/vault/helper/mlock/mlock.go create mode 100644 vendor/github.com/hashicorp/vault/helper/mlock/mlock_unavail.go create mode 100644 vendor/github.com/hashicorp/vault/helper/mlock/mlock_unix.go create mode 100644 vendor/github.com/hashicorp/vault/helper/parseutil/parseutil.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pathmanager/pathmanager.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pgpkeys/encrypt_decrypt.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pgpkeys/flag.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pgpkeys/keybase.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pgpkeys/test_keys.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pluginutil/env.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pluginutil/runner.go create mode 100644 vendor/github.com/hashicorp/vault/helper/pluginutil/tls.go create mode 100644 vendor/github.com/hashicorp/vault/helper/policyutil/policyutil.go create mode 100644 vendor/github.com/hashicorp/vault/helper/reload/reload.go create mode 100644 vendor/github.com/hashicorp/vault/helper/salt/salt.go create mode 100644 vendor/github.com/hashicorp/vault/helper/storagepacker/storagepacker.go create mode 100644 vendor/github.com/hashicorp/vault/helper/storagepacker/types.pb.go create mode 100644 vendor/github.com/hashicorp/vault/helper/storagepacker/types.proto create mode 100644 vendor/github.com/hashicorp/vault/helper/strutil/strutil.go create mode 100644 vendor/github.com/hashicorp/vault/helper/tlsutil/tlsutil.go create mode 100644 vendor/github.com/hashicorp/vault/helper/wrapping/wrapinfo.go create mode 100644 vendor/github.com/hashicorp/vault/helper/xor/xor.go create mode 100644 vendor/github.com/hashicorp/vault/http/cors.go create mode 100644 vendor/github.com/hashicorp/vault/http/handler.go create mode 100644 vendor/github.com/hashicorp/vault/http/help.go create mode 100644 vendor/github.com/hashicorp/vault/http/logical.go create mode 100644 vendor/github.com/hashicorp/vault/http/stub_assets.go create mode 100644 vendor/github.com/hashicorp/vault/http/sys_generate_root.go create mode 100644 vendor/github.com/hashicorp/vault/http/sys_health.go create mode 100644 vendor/github.com/hashicorp/vault/http/sys_init.go create mode 100644 vendor/github.com/hashicorp/vault/http/sys_leader.go create mode 100644 vendor/github.com/hashicorp/vault/http/sys_rekey.go create mode 100644 vendor/github.com/hashicorp/vault/http/sys_seal.go create mode 100644 vendor/github.com/hashicorp/vault/http/testing.go create mode 100644 vendor/github.com/hashicorp/vault/logical/auth.go create mode 100644 vendor/github.com/hashicorp/vault/logical/connection.go create mode 100644 vendor/github.com/hashicorp/vault/logical/error.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/backend.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/field_data.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/field_type.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/lease.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/path.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/path_map.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/path_struct.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/policy_map.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/secret.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/template.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/testing.go create mode 100644 vendor/github.com/hashicorp/vault/logical/framework/wal.go create mode 100644 vendor/github.com/hashicorp/vault/logical/identity.pb.go create mode 100644 vendor/github.com/hashicorp/vault/logical/identity.proto create mode 100644 vendor/github.com/hashicorp/vault/logical/lease.go create mode 100644 vendor/github.com/hashicorp/vault/logical/logical.go create mode 100644 vendor/github.com/hashicorp/vault/logical/request.go create mode 100644 vendor/github.com/hashicorp/vault/logical/response.go create mode 100644 vendor/github.com/hashicorp/vault/logical/response_util.go create mode 100644 vendor/github.com/hashicorp/vault/logical/secret.go create mode 100644 vendor/github.com/hashicorp/vault/logical/storage.go create mode 100644 vendor/github.com/hashicorp/vault/logical/storage_inmem.go create mode 100644 vendor/github.com/hashicorp/vault/logical/system_view.go create mode 100644 vendor/github.com/hashicorp/vault/logical/testing.go create mode 100644 vendor/github.com/hashicorp/vault/logical/token.go create mode 100644 vendor/github.com/hashicorp/vault/logical/translate_response.go create mode 100644 vendor/github.com/hashicorp/vault/physical/cache.go create mode 100644 vendor/github.com/hashicorp/vault/physical/inmem/inmem.go create mode 100644 vendor/github.com/hashicorp/vault/physical/inmem/inmem_ha.go create mode 100644 vendor/github.com/hashicorp/vault/physical/latency.go create mode 100644 vendor/github.com/hashicorp/vault/physical/physical.go create mode 100644 vendor/github.com/hashicorp/vault/physical/physical_access.go create mode 100644 vendor/github.com/hashicorp/vault/physical/physical_view.go create mode 100644 vendor/github.com/hashicorp/vault/physical/testing.go create mode 100644 vendor/github.com/hashicorp/vault/physical/transactions.go create mode 100644 vendor/github.com/hashicorp/vault/physical/types.pb.go create mode 100644 vendor/github.com/hashicorp/vault/physical/types.proto create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/cassandra/cassandra.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/cassandra/connection_producer.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/hana/hana.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/mongodb/connection_producer.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/mongodb/mongodb.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/mongodb/util.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/mssql/mssql.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/mysql/mysql.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/database/postgresql/postgresql.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/connutil.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/helper/database/connutil/sql.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/credsutil.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/helper/database/credsutil/sql.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/helper/database/dbutil/dbutil.go create mode 100644 vendor/github.com/hashicorp/vault/plugins/serve.go create mode 100644 vendor/github.com/hashicorp/vault/shamir/shamir.go create mode 100644 vendor/github.com/hashicorp/vault/shamir/tables.go create mode 100644 vendor/github.com/hashicorp/vault/vault/acl.go create mode 100644 vendor/github.com/hashicorp/vault/vault/audit.go create mode 100644 vendor/github.com/hashicorp/vault/vault/audit_broker.go create mode 100644 vendor/github.com/hashicorp/vault/vault/audited_headers.go create mode 100644 vendor/github.com/hashicorp/vault/vault/auth.go create mode 100644 vendor/github.com/hashicorp/vault/vault/barrier.go create mode 100644 vendor/github.com/hashicorp/vault/vault/barrier_access.go create mode 100644 vendor/github.com/hashicorp/vault/vault/barrier_aes_gcm.go create mode 100644 vendor/github.com/hashicorp/vault/vault/barrier_view.go create mode 100644 vendor/github.com/hashicorp/vault/vault/capabilities.go create mode 100644 vendor/github.com/hashicorp/vault/vault/cluster.go create mode 100644 vendor/github.com/hashicorp/vault/vault/core.go create mode 100644 vendor/github.com/hashicorp/vault/vault/cors.go create mode 100644 vendor/github.com/hashicorp/vault/vault/dynamic_system_view.go create mode 100644 vendor/github.com/hashicorp/vault/vault/expiration.go create mode 100644 vendor/github.com/hashicorp/vault/vault/generate_root.go create mode 100644 vendor/github.com/hashicorp/vault/vault/ha.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_lookup.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_aliases.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_entities.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_group_aliases.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_groups.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_schema.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_structs.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_upgrade.go create mode 100644 vendor/github.com/hashicorp/vault/vault/identity_store_util.go create mode 100644 vendor/github.com/hashicorp/vault/vault/init.go create mode 100644 vendor/github.com/hashicorp/vault/vault/keyring.go create mode 100644 vendor/github.com/hashicorp/vault/vault/logical_cubbyhole.go create mode 100644 vendor/github.com/hashicorp/vault/vault/logical_passthrough.go create mode 100644 vendor/github.com/hashicorp/vault/vault/logical_system.go create mode 100644 vendor/github.com/hashicorp/vault/vault/logical_system_helpers.go create mode 100644 vendor/github.com/hashicorp/vault/vault/mount.go create mode 100644 vendor/github.com/hashicorp/vault/vault/plugin_catalog.go create mode 100644 vendor/github.com/hashicorp/vault/vault/plugin_reload.go create mode 100644 vendor/github.com/hashicorp/vault/vault/policy.go create mode 100644 vendor/github.com/hashicorp/vault/vault/policy_store.go create mode 100644 vendor/github.com/hashicorp/vault/vault/rekey.go create mode 100644 vendor/github.com/hashicorp/vault/vault/request_forwarding.go create mode 100644 vendor/github.com/hashicorp/vault/vault/request_forwarding_service.pb.go create mode 100644 vendor/github.com/hashicorp/vault/vault/request_forwarding_service.proto create mode 100644 vendor/github.com/hashicorp/vault/vault/request_handling.go create mode 100644 vendor/github.com/hashicorp/vault/vault/rollback.go create mode 100644 vendor/github.com/hashicorp/vault/vault/router.go create mode 100644 vendor/github.com/hashicorp/vault/vault/router_access.go create mode 100644 vendor/github.com/hashicorp/vault/vault/seal.go create mode 100644 vendor/github.com/hashicorp/vault/vault/seal_access.go create mode 100644 vendor/github.com/hashicorp/vault/vault/seal_testing.go create mode 100644 vendor/github.com/hashicorp/vault/vault/sealunwrapper.go create mode 100644 vendor/github.com/hashicorp/vault/vault/testing.go create mode 100644 vendor/github.com/hashicorp/vault/vault/token_store.go create mode 100644 vendor/github.com/hashicorp/vault/vault/ui.go create mode 100644 vendor/github.com/hashicorp/vault/vault/util.go create mode 100644 vendor/github.com/hashicorp/vault/vault/wrapping.go create mode 100644 vendor/github.com/hashicorp/vault/version/cgo.go create mode 100644 vendor/github.com/hashicorp/vault/version/version.go create mode 100644 vendor/github.com/hashicorp/vault/version/version_base.go create mode 100644 vendor/github.com/jefferai/jsonx/LICENSE create mode 100644 vendor/github.com/jefferai/jsonx/README.md create mode 100644 vendor/github.com/jefferai/jsonx/jsonx.go create mode 100644 vendor/github.com/keybase/go-crypto/LICENSE create mode 100644 vendor/github.com/keybase/go-crypto/PATENTS create mode 100644 vendor/github.com/keybase/go-crypto/brainpool/brainpool.go create mode 100644 vendor/github.com/keybase/go-crypto/brainpool/rcurve.go create mode 100644 vendor/github.com/keybase/go-crypto/cast5/cast5.go create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/const_amd64.s create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/cswap_amd64.s create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/curve25519.go create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/curve_impl.go create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/doc.go create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/freeze_amd64.s create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/ladderstep_amd64.s create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/mont25519_amd64.go create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/mul_amd64.s create mode 100644 vendor/github.com/keybase/go-crypto/curve25519/square_amd64.s create mode 100644 vendor/github.com/keybase/go-crypto/ed25519/ed25519.go create mode 100644 vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/const.go create mode 100644 vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/armor/armor.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/armor/encode.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/canonical_text.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/ecdh/ecdh.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/elgamal/elgamal.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/errors/errors.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/keys.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/compressed.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/config.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/ecdh.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/encrypted_key.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/literal.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/ocfb.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/one_pass_signature.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/opaque.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/packet.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/public_key.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/public_key_v3.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/reader.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/signature.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/signature_v3.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/symmetric_key_encrypted.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/symmetrically_encrypted.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/userattribute.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/packet/userid.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/patch.sh create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/read.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/s2k/s2k.go create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/sig-v3.patch create mode 100644 vendor/github.com/keybase/go-crypto/openpgp/write.go create mode 100644 vendor/github.com/keybase/go-crypto/rsa/pkcs1v15.go create mode 100644 vendor/github.com/keybase/go-crypto/rsa/pss.go create mode 100644 vendor/github.com/keybase/go-crypto/rsa/rsa.go create mode 100644 vendor/github.com/lib/pq/CONTRIBUTING.md create mode 100644 vendor/github.com/lib/pq/LICENSE.md create mode 100644 vendor/github.com/lib/pq/README.md create mode 100644 vendor/github.com/lib/pq/TESTS.md create mode 100644 vendor/github.com/lib/pq/array.go create mode 100644 vendor/github.com/lib/pq/buf.go create mode 100644 vendor/github.com/lib/pq/conn.go create mode 100644 vendor/github.com/lib/pq/conn_go18.go create mode 100644 vendor/github.com/lib/pq/connector.go create mode 100644 vendor/github.com/lib/pq/copy.go create mode 100644 vendor/github.com/lib/pq/doc.go create mode 100644 vendor/github.com/lib/pq/encode.go create mode 100644 vendor/github.com/lib/pq/error.go create mode 100644 vendor/github.com/lib/pq/notify.go create mode 100644 vendor/github.com/lib/pq/oid/doc.go create mode 100644 vendor/github.com/lib/pq/oid/types.go create mode 100644 vendor/github.com/lib/pq/rows.go create mode 100644 vendor/github.com/lib/pq/ssl.go create mode 100644 vendor/github.com/lib/pq/ssl_go1.7.go create mode 100644 vendor/github.com/lib/pq/ssl_permissions.go create mode 100644 vendor/github.com/lib/pq/ssl_renegotiation.go create mode 100644 vendor/github.com/lib/pq/ssl_windows.go create mode 100644 vendor/github.com/lib/pq/url.go create mode 100644 vendor/github.com/lib/pq/user_posix.go create mode 100644 vendor/github.com/lib/pq/user_windows.go create mode 100644 vendor/github.com/lib/pq/uuid.go create mode 100644 vendor/github.com/oklog/run/LICENSE create mode 100644 vendor/github.com/oklog/run/README.md create mode 100644 vendor/github.com/oklog/run/group.go create mode 100644 vendor/github.com/patrickmn/go-cache/CONTRIBUTORS create mode 100644 vendor/github.com/patrickmn/go-cache/LICENSE create mode 100644 vendor/github.com/patrickmn/go-cache/README.md create mode 100644 vendor/github.com/patrickmn/go-cache/cache.go create mode 100644 vendor/github.com/patrickmn/go-cache/sharded.go create mode 100644 vendor/github.com/ryanuber/go-glob/LICENSE create mode 100644 vendor/github.com/ryanuber/go-glob/README.md create mode 100644 vendor/github.com/ryanuber/go-glob/glob.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/builder.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/string.go create mode 100644 vendor/golang.org/x/crypto/hkdf/hkdf.go create mode 100644 vendor/golang.org/x/crypto/internal/subtle/aliasing.go create mode 100644 vendor/golang.org/x/crypto/md4/md4.go create mode 100644 vendor/golang.org/x/crypto/md4/md4block.go create mode 100644 vendor/golang.org/x/net/context/go19.go create mode 100644 vendor/golang.org/x/net/context/pre_go19.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s create mode 100644 vendor/gopkg.in/inf.v0/LICENSE create mode 100644 vendor/gopkg.in/inf.v0/dec.go create mode 100644 vendor/gopkg.in/inf.v0/rounder.go create mode 100644 vendor/gopkg.in/mgo.v2/LICENSE create mode 100644 vendor/gopkg.in/mgo.v2/Makefile create mode 100644 vendor/gopkg.in/mgo.v2/README.md create mode 100644 vendor/gopkg.in/mgo.v2/auth.go create mode 100644 vendor/gopkg.in/mgo.v2/bson/LICENSE create mode 100644 vendor/gopkg.in/mgo.v2/bson/bson.go create mode 100644 vendor/gopkg.in/mgo.v2/bson/decimal.go create mode 100644 vendor/gopkg.in/mgo.v2/bson/decode.go create mode 100644 vendor/gopkg.in/mgo.v2/bson/encode.go create mode 100644 vendor/gopkg.in/mgo.v2/bson/json.go create mode 100644 vendor/gopkg.in/mgo.v2/bulk.go create mode 100644 vendor/gopkg.in/mgo.v2/cluster.go create mode 100644 vendor/gopkg.in/mgo.v2/doc.go create mode 100644 vendor/gopkg.in/mgo.v2/gridfs.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/LICENSE create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/decode.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/encode.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/extension.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/fold.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/indent.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/scanner.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/stream.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/json/tags.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c create mode 100644 vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h create mode 100644 vendor/gopkg.in/mgo.v2/internal/scram/scram.go create mode 100644 vendor/gopkg.in/mgo.v2/log.go create mode 100644 vendor/gopkg.in/mgo.v2/queue.go create mode 100644 vendor/gopkg.in/mgo.v2/raceoff.go create mode 100644 vendor/gopkg.in/mgo.v2/raceon.go create mode 100644 vendor/gopkg.in/mgo.v2/saslimpl.go create mode 100644 vendor/gopkg.in/mgo.v2/saslstub.go create mode 100644 vendor/gopkg.in/mgo.v2/server.go create mode 100644 vendor/gopkg.in/mgo.v2/session.go create mode 100644 vendor/gopkg.in/mgo.v2/socket.go create mode 100644 vendor/gopkg.in/mgo.v2/stats.go diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE index a4c5efd82..d64569567 100644 --- a/vendor/cloud.google.com/go/LICENSE +++ b/vendor/cloud.google.com/go/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014 Google Inc. + 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. 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 000000000..29272ef26 --- /dev/null +++ b/vendor/cloud.google.com/go/civil/civil.go @@ -0,0 +1,277 @@ +// Copyright 2016 Google LLC +// +// 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 000000000..99a62c629 --- /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 000000000..a58193fd7 --- /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 000000000..a27a7110e --- /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 000000000..d05729db2 --- /dev/null +++ b/vendor/github.com/Jeffail/gabs/gabs_logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef6ea0992f657ca2955a3d8940b3a23367816b411c86afd807ec248f964dbcc0 +size 167771 diff --git a/vendor/github.com/SAP/go-hdb/LICENSE b/vendor/github.com/SAP/go-hdb/LICENSE new file mode 100644 index 000000000..ad410e113 --- /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 000000000..de5f2eaa3 --- /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 000000000..1bb77bf35 --- /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 000000000..9e4b939ba --- /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 000000000..c181cc04d --- /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 000000000..d61bb5a0c --- /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 000000000..4ebc74715 --- /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 000000000..8ffd91a92 --- /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 000000000..b58113d9c --- /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 000000000..3a8df4c92 --- /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 000000000..28518f818 --- /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 000000000..4399a8bf9 --- /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 000000000..3ea663b4e --- /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 000000000..5a6fc48a6 --- /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 000000000..ac23bbc6f --- /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 000000000..50a280781 --- /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 000000000..3b3d8ac01 --- /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 000000000..65026c9f9 --- /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 000000000..e3d563634 --- /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 000000000..d96c161f3 --- /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 000000000..f1c33fdf2 --- /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 000000000..27c781816 --- /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 000000000..32e959ca5 --- /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 000000000..4ae793f83 --- /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 000000000..0b356d34d --- /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 000000000..f23fe2491 --- /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 000000000..579c2a7e2 --- /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 000000000..5f5c0c8e7 --- /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 000000000..8f58e9531 --- /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 000000000..9abe620e3 --- /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 000000000..aa91e0220 --- /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 000000000..297a2d9fd --- /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 000000000..87d765874 --- /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 000000000..a089630e2 --- /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 000000000..434fb97dc --- /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 000000000..27a8ed8ef --- /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 000000000..dc2e0c7e8 --- /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 000000000..9da00951f --- /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 000000000..cba805432 --- /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 000000000..5a3b96ccd --- /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 000000000..e0f0eba7e --- /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 000000000..7a6e1dad8 --- /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 000000000..b5fe36002 --- /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 000000000..92febf169 --- /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 000000000..9d85d146c --- /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 000000000..d32041af4 --- /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 000000000..347126ad9 --- /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 000000000..5a9f4be13 --- /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 000000000..3d5560f97 --- /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 000000000..d7ad7e450 --- /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 000000000..b6aab3b13 --- /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 000000000..14151b6d4 --- /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 000000000..aaea08e6a --- /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 000000000..44cc59c2f --- /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 000000000..33df324c4 --- /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 000000000..230fc45fa --- /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 000000000..7e9133b48 --- /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 000000000..3a9ac78cc --- /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 000000000..c98f70961 --- /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 000000000..749290129 --- /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 000000000..f4f171f30 --- /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 000000000..53555d6bc --- /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 000000000..e5de91e3d --- /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 000000000..3c7756551 --- /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 000000000..584e338bd --- /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 000000000..28ad7d3a4 --- /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 000000000..914032223 --- /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 000000000..c4c22651f --- /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 000000000..9a534f77a --- /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 000000000..882dbf62b --- /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 000000000..be9cf3cb9 --- /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/LICENSE b/vendor/github.com/SermoDigital/jose/LICENSE new file mode 100644 index 000000000..d2d35b66c --- /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 000000000..621862ef9 --- /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 issue #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 000000000..a36a4709b --- /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 000000000..f7275fb2e --- /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 000000000..16cf476ba --- /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 000000000..3ef12ba22 --- /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 000000000..4bd75d2e5 --- /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 000000000..34fbd25ff --- /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 000000000..1cb7f6e09 --- /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 000000000..db3d139e9 --- /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 000000000..80596df33 --- /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 000000000..3847ae2d2 --- /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 000000000..43aeff375 --- /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 000000000..37571f9de --- /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 000000000..c8b8874b2 --- /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 000000000..7abb7bf14 --- /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 000000000..4499a7696 --- /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 000000000..4cc616cfa --- /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 000000000..165836d57 --- /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 000000000..0512a0e40 --- /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 000000000..49e7b976d --- /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 000000000..923fdc224 --- /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 000000000..e5e3abd18 --- /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 000000000..53da1fcf7 --- /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 000000000..58bfd066f --- /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 000000000..f2c406048 --- /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 000000000..525806f4a --- /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 000000000..d3d93bfb5 --- /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 000000000..6004d0fa9 --- /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 000000000..3113269fb --- /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 000000000..96b240d54 --- /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 000000000..feb17126f --- /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 000000000..f366a7a67 --- /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/asaskevich/govalidator/CONTRIBUTING.md b/vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md new file mode 100644 index 000000000..f0f7e3a8a --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/CONTRIBUTING.md @@ -0,0 +1,63 @@ +#### Support +If you do have a contribution to the package, feel free to create a Pull Request or an Issue. + +#### What to contribute +If you don't know what to do, there are some features and functions that need to be done + +- [ ] Refactor code +- [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check +- [ ] Create actual list of contributors and projects that currently using this package +- [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues) +- [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions) +- [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new +- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc +- [ ] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224) +- [ ] Implement fuzzing testing +- [ ] Implement some struct/map/array utilities +- [ ] Implement map/array validation +- [ ] Implement benchmarking +- [ ] Implement batch of examples +- [ ] Look at forks for new features and fixes + +#### Advice +Feel free to create what you want, but keep in mind when you implement new features: +- Code must be clear and readable, names of variables/constants clearly describes what they are doing +- Public functions must be documented and described in source file and added to README.md to the list of available functions +- There are must be unit-tests for any new functions and improvements + +## Financial contributions + +We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/govalidator). +Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. + + +## Credits + + +### Contributors + +Thank you to all the people who have already contributed to govalidator! + + + +### Backers + +Thank you to all our backers! [[Become a backer](https://opencollective.com/govalidator#backer)] + + + + +### Sponsors + +Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/govalidator#sponsor)) + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/asaskevich/govalidator/LICENSE b/vendor/github.com/asaskevich/govalidator/LICENSE new file mode 100644 index 000000000..2f9a31fad --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Alex Saskevich + +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. \ No newline at end of file diff --git a/vendor/github.com/asaskevich/govalidator/README.md b/vendor/github.com/asaskevich/govalidator/README.md new file mode 100644 index 000000000..efd8e64aa --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/README.md @@ -0,0 +1,490 @@ +govalidator +=========== +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![GoDoc](https://godoc.org/github.com/asaskevich/govalidator?status.png)](https://godoc.org/github.com/asaskevich/govalidator) [![Coverage Status](https://img.shields.io/coveralls/asaskevich/govalidator.svg)](https://coveralls.io/r/asaskevich/govalidator?branch=master) [![wercker status](https://app.wercker.com/status/1ec990b09ea86c910d5f08b0e02c6043/s "wercker status")](https://app.wercker.com/project/bykey/1ec990b09ea86c910d5f08b0e02c6043) +[![Build Status](https://travis-ci.org/asaskevich/govalidator.svg?branch=master)](https://travis-ci.org/asaskevich/govalidator) [![Go Report Card](https://goreportcard.com/badge/github.com/asaskevich/govalidator)](https://goreportcard.com/report/github.com/asaskevich/govalidator) [![GoSearch](http://go-search.org/badge?id=github.com%2Fasaskevich%2Fgovalidator)](http://go-search.org/view?id=github.com%2Fasaskevich%2Fgovalidator) [![Backers on Open Collective](https://opencollective.com/govalidator/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/govalidator/sponsors/badge.svg)](#sponsors) + +A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js). + +#### Installation +Make sure that Go is installed on your computer. +Type the following command in your terminal: + + go get github.com/asaskevich/govalidator + +or you can get specified release of the package with `gopkg.in`: + + go get gopkg.in/asaskevich/govalidator.v4 + +After it the package is ready to use. + + +#### Import package in your project +Add following line in your `*.go` file: +```go +import "github.com/asaskevich/govalidator" +``` +If you are unhappy to use long `govalidator`, you can do something like this: +```go +import ( + valid "github.com/asaskevich/govalidator" +) +``` + +#### Activate behavior to require all fields have a validation tag by default +`SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function. + +```go +import "github.com/asaskevich/govalidator" + +func init() { + govalidator.SetFieldsRequiredByDefault(true) +} +``` + +Here's some code to explain it: +```go +// this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): +type exampleStruct struct { + Name string `` + Email string `valid:"email"` +} + +// this, however, will only fail when Email is empty or an invalid email address: +type exampleStruct2 struct { + Name string `valid:"-"` + Email string `valid:"email"` +} + +// lastly, this will only fail when Email is an invalid email address but not when it's empty: +type exampleStruct2 struct { + Name string `valid:"-"` + Email string `valid:"email,optional"` +} +``` + +#### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123)) +##### Custom validator function signature +A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible. +```go +import "github.com/asaskevich/govalidator" + +// old signature +func(i interface{}) bool + +// new signature +func(i interface{}, o interface{}) bool +``` + +##### Adding a custom validator +This was changed to prevent data races when accessing custom validators. +```go +import "github.com/asaskevich/govalidator" + +// before +govalidator.CustomTypeTagMap["customByteArrayValidator"] = CustomTypeValidator(func(i interface{}, o interface{}) bool { + // ... +}) + +// after +govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, o interface{}) bool { + // ... +})) +``` + +#### List of functions: +```go +func Abs(value float64) float64 +func BlackList(str, chars string) string +func ByteLength(str string, params ...string) bool +func CamelCaseToUnderscore(str string) string +func Contains(str, substring string) bool +func Count(array []interface{}, iterator ConditionIterator) int +func Each(array []interface{}, iterator Iterator) +func ErrorByField(e error, field string) string +func ErrorsByField(e error) map[string]string +func Filter(array []interface{}, iterator ConditionIterator) []interface{} +func Find(array []interface{}, iterator ConditionIterator) interface{} +func GetLine(s string, index int) (string, error) +func GetLines(s string) []string +func InRange(value, left, right float64) bool +func IsASCII(str string) bool +func IsAlpha(str string) bool +func IsAlphanumeric(str string) bool +func IsBase64(str string) bool +func IsByteLength(str string, min, max int) bool +func IsCIDR(str string) bool +func IsCreditCard(str string) bool +func IsDNSName(str string) bool +func IsDataURI(str string) bool +func IsDialString(str string) bool +func IsDivisibleBy(str, num string) bool +func IsEmail(str string) bool +func IsFilePath(str string) (bool, int) +func IsFloat(str string) bool +func IsFullWidth(str string) bool +func IsHalfWidth(str string) bool +func IsHexadecimal(str string) bool +func IsHexcolor(str string) bool +func IsHost(str string) bool +func IsIP(str string) bool +func IsIPv4(str string) bool +func IsIPv6(str string) bool +func IsISBN(str string, version int) bool +func IsISBN10(str string) bool +func IsISBN13(str string) bool +func IsISO3166Alpha2(str string) bool +func IsISO3166Alpha3(str string) bool +func IsISO693Alpha2(str string) bool +func IsISO693Alpha3b(str string) bool +func IsISO4217(str string) bool +func IsIn(str string, params ...string) bool +func IsInt(str string) bool +func IsJSON(str string) bool +func IsLatitude(str string) bool +func IsLongitude(str string) bool +func IsLowerCase(str string) bool +func IsMAC(str string) bool +func IsMongoID(str string) bool +func IsMultibyte(str string) bool +func IsNatural(value float64) bool +func IsNegative(value float64) bool +func IsNonNegative(value float64) bool +func IsNonPositive(value float64) bool +func IsNull(str string) bool +func IsNumeric(str string) bool +func IsPort(str string) bool +func IsPositive(value float64) bool +func IsPrintableASCII(str string) bool +func IsRFC3339(str string) bool +func IsRFC3339WithoutZone(str string) bool +func IsRGBcolor(str string) bool +func IsRequestURI(rawurl string) bool +func IsRequestURL(rawurl string) bool +func IsSSN(str string) bool +func IsSemver(str string) bool +func IsTime(str string, format string) bool +func IsURL(str string) bool +func IsUTFDigit(str string) bool +func IsUTFLetter(str string) bool +func IsUTFLetterNumeric(str string) bool +func IsUTFNumeric(str string) bool +func IsUUID(str string) bool +func IsUUIDv3(str string) bool +func IsUUIDv4(str string) bool +func IsUUIDv5(str string) bool +func IsUpperCase(str string) bool +func IsVariableWidth(str string) bool +func IsWhole(value float64) bool +func LeftTrim(str, chars string) string +func Map(array []interface{}, iterator ResultIterator) []interface{} +func Matches(str, pattern string) bool +func NormalizeEmail(str string) (string, error) +func PadBoth(str string, padStr string, padLen int) string +func PadLeft(str string, padStr string, padLen int) string +func PadRight(str string, padStr string, padLen int) string +func Range(str string, params ...string) bool +func RemoveTags(s string) string +func ReplacePattern(str, pattern, replace string) string +func Reverse(s string) string +func RightTrim(str, chars string) string +func RuneLength(str string, params ...string) bool +func SafeFileName(str string) string +func SetFieldsRequiredByDefault(value bool) +func Sign(value float64) float64 +func StringLength(str string, params ...string) bool +func StringMatches(s string, params ...string) bool +func StripLow(str string, keepNewLines bool) string +func ToBoolean(str string) (bool, error) +func ToFloat(str string) (float64, error) +func ToInt(str string) (int64, error) +func ToJSON(obj interface{}) (string, error) +func ToString(obj interface{}) string +func Trim(str, chars string) string +func Truncate(str string, length int, ending string) string +func UnderscoreToCamelCase(s string) string +func ValidateStruct(s interface{}) (bool, error) +func WhiteList(str, chars string) string +type ConditionIterator +type CustomTypeValidator +type Error +func (e Error) Error() string +type Errors +func (es Errors) Error() string +func (es Errors) Errors() []error +type ISO3166Entry +type Iterator +type ParamValidator +type ResultIterator +type UnsupportedTypeError +func (e *UnsupportedTypeError) Error() string +type Validator +``` + +#### Examples +###### IsURL +```go +println(govalidator.IsURL(`http://user@pass:domain.com/path/page`)) +``` +###### ToString +```go +type User struct { + FirstName string + LastName string +} + +str := govalidator.ToString(&User{"John", "Juan"}) +println(str) +``` +###### Each, Map, Filter, Count for slices +Each iterates over the slice/array and calls Iterator for every item +```go +data := []interface{}{1, 2, 3, 4, 5} +var fn govalidator.Iterator = func(value interface{}, index int) { + println(value.(int)) +} +govalidator.Each(data, fn) +``` +```go +data := []interface{}{1, 2, 3, 4, 5} +var fn govalidator.ResultIterator = func(value interface{}, index int) interface{} { + return value.(int) * 3 +} +_ = govalidator.Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15} +``` +```go +data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +var fn govalidator.ConditionIterator = func(value interface{}, index int) bool { + return value.(int)%2 == 0 +} +_ = govalidator.Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10} +_ = govalidator.Count(data, fn) // result = 5 +``` +###### ValidateStruct [#2](https://github.com/asaskevich/govalidator/pull/2) +If you want to validate structs, you can use tag `valid` for any field in your structure. All validators used with this field in one tag are separated by comma. If you want to skip validation, place `-` in your tag. If you need a validator that is not on the list below, you can add it like this: +```go +govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { + return str == "duck" +}) +``` +For completely custom validators (interface-based), see below. + +Here is a list of available validators for struct fields (validator - used function): +```go +"email": IsEmail, +"url": IsURL, +"dialstring": IsDialString, +"requrl": IsRequestURL, +"requri": IsRequestURI, +"alpha": IsAlpha, +"utfletter": IsUTFLetter, +"alphanum": IsAlphanumeric, +"utfletternum": IsUTFLetterNumeric, +"numeric": IsNumeric, +"utfnumeric": IsUTFNumeric, +"utfdigit": IsUTFDigit, +"hexadecimal": IsHexadecimal, +"hexcolor": IsHexcolor, +"rgbcolor": IsRGBcolor, +"lowercase": IsLowerCase, +"uppercase": IsUpperCase, +"int": IsInt, +"float": IsFloat, +"null": IsNull, +"uuid": IsUUID, +"uuidv3": IsUUIDv3, +"uuidv4": IsUUIDv4, +"uuidv5": IsUUIDv5, +"creditcard": IsCreditCard, +"isbn10": IsISBN10, +"isbn13": IsISBN13, +"json": IsJSON, +"multibyte": IsMultibyte, +"ascii": IsASCII, +"printableascii": IsPrintableASCII, +"fullwidth": IsFullWidth, +"halfwidth": IsHalfWidth, +"variablewidth": IsVariableWidth, +"base64": IsBase64, +"datauri": IsDataURI, +"ip": IsIP, +"port": IsPort, +"ipv4": IsIPv4, +"ipv6": IsIPv6, +"dns": IsDNSName, +"host": IsHost, +"mac": IsMAC, +"latitude": IsLatitude, +"longitude": IsLongitude, +"ssn": IsSSN, +"semver": IsSemver, +"rfc3339": IsRFC3339, +"rfc3339WithoutZone": IsRFC3339WithoutZone, +"ISO3166Alpha2": IsISO3166Alpha2, +"ISO3166Alpha3": IsISO3166Alpha3, +``` +Validators with parameters + +```go +"range(min|max)": Range, +"length(min|max)": ByteLength, +"runelength(min|max)": RuneLength, +"matches(pattern)": StringMatches, +"in(string1|string2|...|stringN)": IsIn, +``` + +And here is small example of usage: +```go +type Post struct { + Title string `valid:"alphanum,required"` + Message string `valid:"duck,ascii"` + AuthorIP string `valid:"ipv4"` + Date string `valid:"-"` +} +post := &Post{ + Title: "My Example Post", + Message: "duck", + AuthorIP: "123.234.54.3", +} + +// Add your own struct validation tags +govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool { + return str == "duck" +}) + +result, err := govalidator.ValidateStruct(post) +if err != nil { + println("error: " + err.Error()) +} +println(result) +``` +###### WhiteList +```go +// Remove all characters from string ignoring characters between "a" and "z" +println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa") +``` + +###### Custom validation functions +Custom validation using your own domain specific validators is also available - here's an example of how to use it: +```go +import "github.com/asaskevich/govalidator" + +type CustomByteArray [6]byte // custom types are supported and can be validated + +type StructWithCustomByteArray struct { + ID CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence + Email string `valid:"email"` + CustomMinLength int `valid:"-"` +} + +govalidator.CustomTypeTagMap.Set("customByteArrayValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool { + switch v := context.(type) { // you can type switch on the context interface being validated + case StructWithCustomByteArray: + // you can check and validate against some other field in the context, + // return early or not validate against the context at all – your choice + case SomeOtherType: + // ... + default: + // expecting some other type? Throw/panic here or continue + } + + switch v := i.(type) { // type switch on the struct field being validated + case CustomByteArray: + for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes + if e != 0 { + return true + } + } + } + return false +})) +govalidator.CustomTypeTagMap.Set("customMinLengthValidator", CustomTypeValidator(func(i interface{}, context interface{}) bool { + switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation + case StructWithCustomByteArray: + return len(v.ID) >= v.CustomMinLength + } + return false +})) +``` + +###### Custom error messages +Custom error messages are supported via annotations by adding the `~` separator - here's an example of how to use it: +```go +type Ticket struct { + Id int64 `json:"id"` + FirstName string `json:"firstname" valid:"required~First name is blank"` +} +``` + +#### Notes +Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator). +Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator). + +#### Support +If you do have a contribution to the package, feel free to create a Pull Request or an Issue. + +#### What to contribute +If you don't know what to do, there are some features and functions that need to be done + +- [ ] Refactor code +- [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check +- [ ] Create actual list of contributors and projects that currently using this package +- [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues) +- [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions) +- [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new +- [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc +- [ ] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224) +- [ ] Implement fuzzing testing +- [ ] Implement some struct/map/array utilities +- [ ] Implement map/array validation +- [ ] Implement benchmarking +- [ ] Implement batch of examples +- [ ] Look at forks for new features and fixes + +#### Advice +Feel free to create what you want, but keep in mind when you implement new features: +- Code must be clear and readable, names of variables/constants clearly describes what they are doing +- Public functions must be documented and described in source file and added to README.md to the list of available functions +- There are must be unit-tests for any new functions and improvements + +## Credits +### Contributors + +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. + +#### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors) +* [Daniel Lohse](https://github.com/annismckenzie) +* [Attila Oláh](https://github.com/attilaolah) +* [Daniel Korner](https://github.com/Dadie) +* [Steven Wilkin](https://github.com/stevenwilkin) +* [Deiwin Sarjas](https://github.com/deiwin) +* [Noah Shibley](https://github.com/slugmobile) +* [Nathan Davies](https://github.com/nathj07) +* [Matt Sanford](https://github.com/mzsanford) +* [Simon ccl1115](https://github.com/ccl1115) + + + + +### Backers + +Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/govalidator#backer)] + + + + +### Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/govalidator#sponsor)] + + + + + + + + + + + + + diff --git a/vendor/github.com/asaskevich/govalidator/arrays.go b/vendor/github.com/asaskevich/govalidator/arrays.go new file mode 100644 index 000000000..5bace2654 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/arrays.go @@ -0,0 +1,58 @@ +package govalidator + +// Iterator is the function that accepts element of slice/array and its index +type Iterator func(interface{}, int) + +// ResultIterator is the function that accepts element of slice/array and its index and returns any result +type ResultIterator func(interface{}, int) interface{} + +// ConditionIterator is the function that accepts element of slice/array and its index and returns boolean +type ConditionIterator func(interface{}, int) bool + +// Each iterates over the slice and apply Iterator to every item +func Each(array []interface{}, iterator Iterator) { + for index, data := range array { + iterator(data, index) + } +} + +// Map iterates over the slice and apply ResultIterator to every item. Returns new slice as a result. +func Map(array []interface{}, iterator ResultIterator) []interface{} { + var result = make([]interface{}, len(array)) + for index, data := range array { + result[index] = iterator(data, index) + } + return result +} + +// Find iterates over the slice and apply ConditionIterator to every item. Returns first item that meet ConditionIterator or nil otherwise. +func Find(array []interface{}, iterator ConditionIterator) interface{} { + for index, data := range array { + if iterator(data, index) { + return data + } + } + return nil +} + +// Filter iterates over the slice and apply ConditionIterator to every item. Returns new slice. +func Filter(array []interface{}, iterator ConditionIterator) []interface{} { + var result = make([]interface{}, 0) + for index, data := range array { + if iterator(data, index) { + result = append(result, data) + } + } + return result +} + +// Count iterates over the slice and apply ConditionIterator to every item. Returns count of items that meets ConditionIterator. +func Count(array []interface{}, iterator ConditionIterator) int { + count := 0 + for index, data := range array { + if iterator(data, index) { + count = count + 1 + } + } + return count +} diff --git a/vendor/github.com/asaskevich/govalidator/converter.go b/vendor/github.com/asaskevich/govalidator/converter.go new file mode 100644 index 000000000..cf1e5d569 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/converter.go @@ -0,0 +1,64 @@ +package govalidator + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" +) + +// ToString convert the input to a string. +func ToString(obj interface{}) string { + res := fmt.Sprintf("%v", obj) + return string(res) +} + +// ToJSON convert the input to a valid JSON string +func ToJSON(obj interface{}) (string, error) { + res, err := json.Marshal(obj) + if err != nil { + res = []byte("") + } + return string(res), err +} + +// ToFloat convert the input string to a float, or 0.0 if the input is not a float. +func ToFloat(str string) (float64, error) { + res, err := strconv.ParseFloat(str, 64) + if err != nil { + res = 0.0 + } + return res, err +} + +// ToInt convert the input string or any int type to an integer type 64, or 0 if the input is not an integer. +func ToInt(value interface{}) (res int64, err error) { + val := reflect.ValueOf(value) + + switch value.(type) { + case int, int8, int16, int32, int64: + res = val.Int() + case uint, uint8, uint16, uint32, uint64: + res = int64(val.Uint()) + case string: + if IsInt(val.String()) { + res, err = strconv.ParseInt(val.String(), 0, 64) + if err != nil { + res = 0 + } + } else { + err = fmt.Errorf("math: square root of negative number %g", value) + res = 0 + } + default: + err = fmt.Errorf("math: square root of negative number %g", value) + res = 0 + } + + return +} + +// ToBoolean convert the input string to a boolean. +func ToBoolean(str string) (bool, error) { + return strconv.ParseBool(str) +} diff --git a/vendor/github.com/asaskevich/govalidator/error.go b/vendor/github.com/asaskevich/govalidator/error.go new file mode 100644 index 000000000..b9c32079b --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/error.go @@ -0,0 +1,36 @@ +package govalidator + +import "strings" + +// Errors is an array of multiple errors and conforms to the error interface. +type Errors []error + +// Errors returns itself. +func (es Errors) Errors() []error { + return es +} + +func (es Errors) Error() string { + var errs []string + for _, e := range es { + errs = append(errs, e.Error()) + } + return strings.Join(errs, ";") +} + +// Error encapsulates a name, an error and whether there's a custom error message or not. +type Error struct { + Name string + Err error + CustomErrorMessageExists bool + + // Validator indicates the name of the validator that failed + Validator string +} + +func (e Error) Error() string { + if e.CustomErrorMessageExists { + return e.Err.Error() + } + return e.Name + ": " + e.Err.Error() +} diff --git a/vendor/github.com/asaskevich/govalidator/numerics.go b/vendor/github.com/asaskevich/govalidator/numerics.go new file mode 100644 index 000000000..7e6c652e1 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/numerics.go @@ -0,0 +1,97 @@ +package govalidator + +import ( + "math" + "reflect" +) + +// Abs returns absolute value of number +func Abs(value float64) float64 { + return math.Abs(value) +} + +// Sign returns signum of number: 1 in case of value > 0, -1 in case of value < 0, 0 otherwise +func Sign(value float64) float64 { + if value > 0 { + return 1 + } else if value < 0 { + return -1 + } else { + return 0 + } +} + +// IsNegative returns true if value < 0 +func IsNegative(value float64) bool { + return value < 0 +} + +// IsPositive returns true if value > 0 +func IsPositive(value float64) bool { + return value > 0 +} + +// IsNonNegative returns true if value >= 0 +func IsNonNegative(value float64) bool { + return value >= 0 +} + +// IsNonPositive returns true if value <= 0 +func IsNonPositive(value float64) bool { + return value <= 0 +} + +// InRange returns true if value lies between left and right border +func InRangeInt(value, left, right interface{}) bool { + value64, _ := ToInt(value) + left64, _ := ToInt(left) + right64, _ := ToInt(right) + if left64 > right64 { + left64, right64 = right64, left64 + } + return value64 >= left64 && value64 <= right64 +} + +// InRange returns true if value lies between left and right border +func InRangeFloat32(value, left, right float32) bool { + if left > right { + left, right = right, left + } + return value >= left && value <= right +} + +// InRange returns true if value lies between left and right border +func InRangeFloat64(value, left, right float64) bool { + if left > right { + left, right = right, left + } + return value >= left && value <= right +} + +// InRange returns true if value lies between left and right border, generic type to handle int, float32 or float64, all types must the same type +func InRange(value interface{}, left interface{}, right interface{}) bool { + + reflectValue := reflect.TypeOf(value).Kind() + reflectLeft := reflect.TypeOf(left).Kind() + reflectRight := reflect.TypeOf(right).Kind() + + if reflectValue == reflect.Int && reflectLeft == reflect.Int && reflectRight == reflect.Int { + return InRangeInt(value.(int), left.(int), right.(int)) + } else if reflectValue == reflect.Float32 && reflectLeft == reflect.Float32 && reflectRight == reflect.Float32 { + return InRangeFloat32(value.(float32), left.(float32), right.(float32)) + } else if reflectValue == reflect.Float64 && reflectLeft == reflect.Float64 && reflectRight == reflect.Float64 { + return InRangeFloat64(value.(float64), left.(float64), right.(float64)) + } else { + return false + } +} + +// IsWhole returns true if value is whole number +func IsWhole(value float64) bool { + return math.Remainder(value, 1) == 0 +} + +// IsNatural returns true if value is natural number (positive and whole) +func IsNatural(value float64) bool { + return IsWhole(value) && IsPositive(value) +} diff --git a/vendor/github.com/asaskevich/govalidator/patterns.go b/vendor/github.com/asaskevich/govalidator/patterns.go new file mode 100644 index 000000000..b7375bd03 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/patterns.go @@ -0,0 +1,97 @@ +package govalidator + +import "regexp" + +// Basic regular expressions for validating strings +const ( + Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" + CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$" + ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$" + ISBN13 string = "^(?:[0-9]{13})$" + UUID3 string = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" + UUID4 string = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + UUID5 string = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + UUID string = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" + Alpha string = "^[a-zA-Z]+$" + Alphanumeric string = "^[a-zA-Z0-9]+$" + Numeric string = "^[0-9]+$" + Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$" + Float string = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$" + Hexadecimal string = "^[0-9a-fA-F]+$" + Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" + RGBcolor string = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$" + ASCII string = "^[\x00-\x7F]+$" + Multibyte string = "[^\x00-\x7F]" + FullWidth string = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" + HalfWidth string = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" + Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" + PrintableASCII string = "^[\x20-\x7E]+$" + DataURI string = "^data:.+\\/(.+);base64$" + Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" + Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" + DNSName string = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$` + IP string = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` + URLSchema string = `((ftp|tcp|udp|wss?|https?):\/\/)` + URLUsername string = `(\S+(:\S*)?@)` + URLPath string = `((\/|\?|#)[^\s]*)` + URLPort string = `(:(\d{1,5}))` + URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))` + URLSubdomain string = `((www\.)|([a-zA-Z0-9]([-\.][-\._a-zA-Z0-9]+)*))` + URL string = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$` + SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` + WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$` + UnixPath string = `^(/[^/\x00]*)+/?$` + Semver string = "^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$" + tagName string = "valid" + hasLowerCase string = ".*[[:lower:]]" + hasUpperCase string = ".*[[:upper:]]" +) + +// Used by IsFilePath func +const ( + // Unknown is unresolved OS type + Unknown = iota + // Win is Windows type + Win + // Unix is *nix OS types + Unix +) + +var ( + userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$") + hostRegexp = regexp.MustCompile("^[^\\s]+\\.[^\\s]+$") + userDotRegexp = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})") + rxEmail = regexp.MustCompile(Email) + rxCreditCard = regexp.MustCompile(CreditCard) + rxISBN10 = regexp.MustCompile(ISBN10) + rxISBN13 = regexp.MustCompile(ISBN13) + rxUUID3 = regexp.MustCompile(UUID3) + rxUUID4 = regexp.MustCompile(UUID4) + rxUUID5 = regexp.MustCompile(UUID5) + rxUUID = regexp.MustCompile(UUID) + rxAlpha = regexp.MustCompile(Alpha) + rxAlphanumeric = regexp.MustCompile(Alphanumeric) + rxNumeric = regexp.MustCompile(Numeric) + rxInt = regexp.MustCompile(Int) + rxFloat = regexp.MustCompile(Float) + rxHexadecimal = regexp.MustCompile(Hexadecimal) + rxHexcolor = regexp.MustCompile(Hexcolor) + rxRGBcolor = regexp.MustCompile(RGBcolor) + rxASCII = regexp.MustCompile(ASCII) + rxPrintableASCII = regexp.MustCompile(PrintableASCII) + rxMultibyte = regexp.MustCompile(Multibyte) + rxFullWidth = regexp.MustCompile(FullWidth) + rxHalfWidth = regexp.MustCompile(HalfWidth) + rxBase64 = regexp.MustCompile(Base64) + rxDataURI = regexp.MustCompile(DataURI) + rxLatitude = regexp.MustCompile(Latitude) + rxLongitude = regexp.MustCompile(Longitude) + rxDNSName = regexp.MustCompile(DNSName) + rxURL = regexp.MustCompile(URL) + rxSSN = regexp.MustCompile(SSN) + rxWinPath = regexp.MustCompile(WinPath) + rxUnixPath = regexp.MustCompile(UnixPath) + rxSemver = regexp.MustCompile(Semver) + rxHasLowerCase = regexp.MustCompile(hasLowerCase) + rxHasUpperCase = regexp.MustCompile(hasUpperCase) +) diff --git a/vendor/github.com/asaskevich/govalidator/types.go b/vendor/github.com/asaskevich/govalidator/types.go new file mode 100644 index 000000000..ddd30b122 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/types.go @@ -0,0 +1,616 @@ +package govalidator + +import ( + "reflect" + "regexp" + "sync" +) + +// Validator is a wrapper for a validator function that returns bool and accepts string. +type Validator func(str string) bool + +// CustomTypeValidator is a wrapper for validator functions that returns bool and accepts any type. +// The second parameter should be the context (in the case of validating a struct: the whole object being validated). +type CustomTypeValidator func(i interface{}, o interface{}) bool + +// ParamValidator is a wrapper for validator functions that accepts additional parameters. +type ParamValidator func(str string, params ...string) bool +type tagOptionsMap map[string]string + +// UnsupportedTypeError is a wrapper for reflect.Type +type UnsupportedTypeError struct { + Type reflect.Type +} + +// stringValues is a slice of reflect.Value holding *reflect.StringValue. +// It implements the methods to sort by string. +type stringValues []reflect.Value + +// ParamTagMap is a map of functions accept variants parameters +var ParamTagMap = map[string]ParamValidator{ + "length": ByteLength, + "range": Range, + "runelength": RuneLength, + "stringlength": StringLength, + "matches": StringMatches, + "in": isInRaw, + "rsapub": IsRsaPub, +} + +// ParamTagRegexMap maps param tags to their respective regexes. +var ParamTagRegexMap = map[string]*regexp.Regexp{ + "range": regexp.MustCompile("^range\\((\\d+)\\|(\\d+)\\)$"), + "length": regexp.MustCompile("^length\\((\\d+)\\|(\\d+)\\)$"), + "runelength": regexp.MustCompile("^runelength\\((\\d+)\\|(\\d+)\\)$"), + "stringlength": regexp.MustCompile("^stringlength\\((\\d+)\\|(\\d+)\\)$"), + "in": regexp.MustCompile(`^in\((.*)\)`), + "matches": regexp.MustCompile(`^matches\((.+)\)$`), + "rsapub": regexp.MustCompile("^rsapub\\((\\d+)\\)$"), +} + +type customTypeTagMap struct { + validators map[string]CustomTypeValidator + + sync.RWMutex +} + +func (tm *customTypeTagMap) Get(name string) (CustomTypeValidator, bool) { + tm.RLock() + defer tm.RUnlock() + v, ok := tm.validators[name] + return v, ok +} + +func (tm *customTypeTagMap) Set(name string, ctv CustomTypeValidator) { + tm.Lock() + defer tm.Unlock() + tm.validators[name] = ctv +} + +// CustomTypeTagMap is a map of functions that can be used as tags for ValidateStruct function. +// Use this to validate compound or custom types that need to be handled as a whole, e.g. +// `type UUID [16]byte` (this would be handled as an array of bytes). +var CustomTypeTagMap = &customTypeTagMap{validators: make(map[string]CustomTypeValidator)} + +// TagMap is a map of functions, that can be used as tags for ValidateStruct function. +var TagMap = map[string]Validator{ + "email": IsEmail, + "url": IsURL, + "dialstring": IsDialString, + "requrl": IsRequestURL, + "requri": IsRequestURI, + "alpha": IsAlpha, + "utfletter": IsUTFLetter, + "alphanum": IsAlphanumeric, + "utfletternum": IsUTFLetterNumeric, + "numeric": IsNumeric, + "utfnumeric": IsUTFNumeric, + "utfdigit": IsUTFDigit, + "hexadecimal": IsHexadecimal, + "hexcolor": IsHexcolor, + "rgbcolor": IsRGBcolor, + "lowercase": IsLowerCase, + "uppercase": IsUpperCase, + "int": IsInt, + "float": IsFloat, + "null": IsNull, + "uuid": IsUUID, + "uuidv3": IsUUIDv3, + "uuidv4": IsUUIDv4, + "uuidv5": IsUUIDv5, + "creditcard": IsCreditCard, + "isbn10": IsISBN10, + "isbn13": IsISBN13, + "json": IsJSON, + "multibyte": IsMultibyte, + "ascii": IsASCII, + "printableascii": IsPrintableASCII, + "fullwidth": IsFullWidth, + "halfwidth": IsHalfWidth, + "variablewidth": IsVariableWidth, + "base64": IsBase64, + "datauri": IsDataURI, + "ip": IsIP, + "port": IsPort, + "ipv4": IsIPv4, + "ipv6": IsIPv6, + "dns": IsDNSName, + "host": IsHost, + "mac": IsMAC, + "latitude": IsLatitude, + "longitude": IsLongitude, + "ssn": IsSSN, + "semver": IsSemver, + "rfc3339": IsRFC3339, + "rfc3339WithoutZone": IsRFC3339WithoutZone, + "ISO3166Alpha2": IsISO3166Alpha2, + "ISO3166Alpha3": IsISO3166Alpha3, + "ISO4217": IsISO4217, +} + +// ISO3166Entry stores country codes +type ISO3166Entry struct { + EnglishShortName string + FrenchShortName string + Alpha2Code string + Alpha3Code string + Numeric string +} + +//ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes" +var ISO3166List = []ISO3166Entry{ + {"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"}, + {"Albania", "Albanie (l')", "AL", "ALB", "008"}, + {"Antarctica", "Antarctique (l')", "AQ", "ATA", "010"}, + {"Algeria", "Algérie (l')", "DZ", "DZA", "012"}, + {"American Samoa", "Samoa américaines (les)", "AS", "ASM", "016"}, + {"Andorra", "Andorre (l')", "AD", "AND", "020"}, + {"Angola", "Angola (l')", "AO", "AGO", "024"}, + {"Antigua and Barbuda", "Antigua-et-Barbuda", "AG", "ATG", "028"}, + {"Azerbaijan", "Azerbaïdjan (l')", "AZ", "AZE", "031"}, + {"Argentina", "Argentine (l')", "AR", "ARG", "032"}, + {"Australia", "Australie (l')", "AU", "AUS", "036"}, + {"Austria", "Autriche (l')", "AT", "AUT", "040"}, + {"Bahamas (the)", "Bahamas (les)", "BS", "BHS", "044"}, + {"Bahrain", "Bahreïn", "BH", "BHR", "048"}, + {"Bangladesh", "Bangladesh (le)", "BD", "BGD", "050"}, + {"Armenia", "Arménie (l')", "AM", "ARM", "051"}, + {"Barbados", "Barbade (la)", "BB", "BRB", "052"}, + {"Belgium", "Belgique (la)", "BE", "BEL", "056"}, + {"Bermuda", "Bermudes (les)", "BM", "BMU", "060"}, + {"Bhutan", "Bhoutan (le)", "BT", "BTN", "064"}, + {"Bolivia (Plurinational State of)", "Bolivie (État plurinational de)", "BO", "BOL", "068"}, + {"Bosnia and Herzegovina", "Bosnie-Herzégovine (la)", "BA", "BIH", "070"}, + {"Botswana", "Botswana (le)", "BW", "BWA", "072"}, + {"Bouvet Island", "Bouvet (l'Île)", "BV", "BVT", "074"}, + {"Brazil", "Brésil (le)", "BR", "BRA", "076"}, + {"Belize", "Belize (le)", "BZ", "BLZ", "084"}, + {"British Indian Ocean Territory (the)", "Indien (le Territoire britannique de l'océan)", "IO", "IOT", "086"}, + {"Solomon Islands", "Salomon (Îles)", "SB", "SLB", "090"}, + {"Virgin Islands (British)", "Vierges britanniques (les Îles)", "VG", "VGB", "092"}, + {"Brunei Darussalam", "Brunéi Darussalam (le)", "BN", "BRN", "096"}, + {"Bulgaria", "Bulgarie (la)", "BG", "BGR", "100"}, + {"Myanmar", "Myanmar (le)", "MM", "MMR", "104"}, + {"Burundi", "Burundi (le)", "BI", "BDI", "108"}, + {"Belarus", "Bélarus (le)", "BY", "BLR", "112"}, + {"Cambodia", "Cambodge (le)", "KH", "KHM", "116"}, + {"Cameroon", "Cameroun (le)", "CM", "CMR", "120"}, + {"Canada", "Canada (le)", "CA", "CAN", "124"}, + {"Cabo Verde", "Cabo Verde", "CV", "CPV", "132"}, + {"Cayman Islands (the)", "Caïmans (les Îles)", "KY", "CYM", "136"}, + {"Central African Republic (the)", "République centrafricaine (la)", "CF", "CAF", "140"}, + {"Sri Lanka", "Sri Lanka", "LK", "LKA", "144"}, + {"Chad", "Tchad (le)", "TD", "TCD", "148"}, + {"Chile", "Chili (le)", "CL", "CHL", "152"}, + {"China", "Chine (la)", "CN", "CHN", "156"}, + {"Taiwan (Province of China)", "Taïwan (Province de Chine)", "TW", "TWN", "158"}, + {"Christmas Island", "Christmas (l'Île)", "CX", "CXR", "162"}, + {"Cocos (Keeling) Islands (the)", "Cocos (les Îles)/ Keeling (les Îles)", "CC", "CCK", "166"}, + {"Colombia", "Colombie (la)", "CO", "COL", "170"}, + {"Comoros (the)", "Comores (les)", "KM", "COM", "174"}, + {"Mayotte", "Mayotte", "YT", "MYT", "175"}, + {"Congo (the)", "Congo (le)", "CG", "COG", "178"}, + {"Congo (the Democratic Republic of the)", "Congo (la République démocratique du)", "CD", "COD", "180"}, + {"Cook Islands (the)", "Cook (les Îles)", "CK", "COK", "184"}, + {"Costa Rica", "Costa Rica (le)", "CR", "CRI", "188"}, + {"Croatia", "Croatie (la)", "HR", "HRV", "191"}, + {"Cuba", "Cuba", "CU", "CUB", "192"}, + {"Cyprus", "Chypre", "CY", "CYP", "196"}, + {"Czech Republic (the)", "tchèque (la République)", "CZ", "CZE", "203"}, + {"Benin", "Bénin (le)", "BJ", "BEN", "204"}, + {"Denmark", "Danemark (le)", "DK", "DNK", "208"}, + {"Dominica", "Dominique (la)", "DM", "DMA", "212"}, + {"Dominican Republic (the)", "dominicaine (la République)", "DO", "DOM", "214"}, + {"Ecuador", "Équateur (l')", "EC", "ECU", "218"}, + {"El Salvador", "El Salvador", "SV", "SLV", "222"}, + {"Equatorial Guinea", "Guinée équatoriale (la)", "GQ", "GNQ", "226"}, + {"Ethiopia", "Éthiopie (l')", "ET", "ETH", "231"}, + {"Eritrea", "Érythrée (l')", "ER", "ERI", "232"}, + {"Estonia", "Estonie (l')", "EE", "EST", "233"}, + {"Faroe Islands (the)", "Féroé (les Îles)", "FO", "FRO", "234"}, + {"Falkland Islands (the) [Malvinas]", "Falkland (les Îles)/Malouines (les Îles)", "FK", "FLK", "238"}, + {"South Georgia and the South Sandwich Islands", "Géorgie du Sud-et-les Îles Sandwich du Sud (la)", "GS", "SGS", "239"}, + {"Fiji", "Fidji (les)", "FJ", "FJI", "242"}, + {"Finland", "Finlande (la)", "FI", "FIN", "246"}, + {"Åland Islands", "Åland(les Îles)", "AX", "ALA", "248"}, + {"France", "France (la)", "FR", "FRA", "250"}, + {"French Guiana", "Guyane française (la )", "GF", "GUF", "254"}, + {"French Polynesia", "Polynésie française (la)", "PF", "PYF", "258"}, + {"French Southern Territories (the)", "Terres australes françaises (les)", "TF", "ATF", "260"}, + {"Djibouti", "Djibouti", "DJ", "DJI", "262"}, + {"Gabon", "Gabon (le)", "GA", "GAB", "266"}, + {"Georgia", "Géorgie (la)", "GE", "GEO", "268"}, + {"Gambia (the)", "Gambie (la)", "GM", "GMB", "270"}, + {"Palestine, State of", "Palestine, État de", "PS", "PSE", "275"}, + {"Germany", "Allemagne (l')", "DE", "DEU", "276"}, + {"Ghana", "Ghana (le)", "GH", "GHA", "288"}, + {"Gibraltar", "Gibraltar", "GI", "GIB", "292"}, + {"Kiribati", "Kiribati", "KI", "KIR", "296"}, + {"Greece", "Grèce (la)", "GR", "GRC", "300"}, + {"Greenland", "Groenland (le)", "GL", "GRL", "304"}, + {"Grenada", "Grenade (la)", "GD", "GRD", "308"}, + {"Guadeloupe", "Guadeloupe (la)", "GP", "GLP", "312"}, + {"Guam", "Guam", "GU", "GUM", "316"}, + {"Guatemala", "Guatemala (le)", "GT", "GTM", "320"}, + {"Guinea", "Guinée (la)", "GN", "GIN", "324"}, + {"Guyana", "Guyana (le)", "GY", "GUY", "328"}, + {"Haiti", "Haïti", "HT", "HTI", "332"}, + {"Heard Island and McDonald Islands", "Heard-et-Îles MacDonald (l'Île)", "HM", "HMD", "334"}, + {"Holy See (the)", "Saint-Siège (le)", "VA", "VAT", "336"}, + {"Honduras", "Honduras (le)", "HN", "HND", "340"}, + {"Hong Kong", "Hong Kong", "HK", "HKG", "344"}, + {"Hungary", "Hongrie (la)", "HU", "HUN", "348"}, + {"Iceland", "Islande (l')", "IS", "ISL", "352"}, + {"India", "Inde (l')", "IN", "IND", "356"}, + {"Indonesia", "Indonésie (l')", "ID", "IDN", "360"}, + {"Iran (Islamic Republic of)", "Iran (République Islamique d')", "IR", "IRN", "364"}, + {"Iraq", "Iraq (l')", "IQ", "IRQ", "368"}, + {"Ireland", "Irlande (l')", "IE", "IRL", "372"}, + {"Israel", "Israël", "IL", "ISR", "376"}, + {"Italy", "Italie (l')", "IT", "ITA", "380"}, + {"Côte d'Ivoire", "Côte d'Ivoire (la)", "CI", "CIV", "384"}, + {"Jamaica", "Jamaïque (la)", "JM", "JAM", "388"}, + {"Japan", "Japon (le)", "JP", "JPN", "392"}, + {"Kazakhstan", "Kazakhstan (le)", "KZ", "KAZ", "398"}, + {"Jordan", "Jordanie (la)", "JO", "JOR", "400"}, + {"Kenya", "Kenya (le)", "KE", "KEN", "404"}, + {"Korea (the Democratic People's Republic of)", "Corée (la République populaire démocratique de)", "KP", "PRK", "408"}, + {"Korea (the Republic of)", "Corée (la République de)", "KR", "KOR", "410"}, + {"Kuwait", "Koweït (le)", "KW", "KWT", "414"}, + {"Kyrgyzstan", "Kirghizistan (le)", "KG", "KGZ", "417"}, + {"Lao People's Democratic Republic (the)", "Lao, République démocratique populaire", "LA", "LAO", "418"}, + {"Lebanon", "Liban (le)", "LB", "LBN", "422"}, + {"Lesotho", "Lesotho (le)", "LS", "LSO", "426"}, + {"Latvia", "Lettonie (la)", "LV", "LVA", "428"}, + {"Liberia", "Libéria (le)", "LR", "LBR", "430"}, + {"Libya", "Libye (la)", "LY", "LBY", "434"}, + {"Liechtenstein", "Liechtenstein (le)", "LI", "LIE", "438"}, + {"Lithuania", "Lituanie (la)", "LT", "LTU", "440"}, + {"Luxembourg", "Luxembourg (le)", "LU", "LUX", "442"}, + {"Macao", "Macao", "MO", "MAC", "446"}, + {"Madagascar", "Madagascar", "MG", "MDG", "450"}, + {"Malawi", "Malawi (le)", "MW", "MWI", "454"}, + {"Malaysia", "Malaisie (la)", "MY", "MYS", "458"}, + {"Maldives", "Maldives (les)", "MV", "MDV", "462"}, + {"Mali", "Mali (le)", "ML", "MLI", "466"}, + {"Malta", "Malte", "MT", "MLT", "470"}, + {"Martinique", "Martinique (la)", "MQ", "MTQ", "474"}, + {"Mauritania", "Mauritanie (la)", "MR", "MRT", "478"}, + {"Mauritius", "Maurice", "MU", "MUS", "480"}, + {"Mexico", "Mexique (le)", "MX", "MEX", "484"}, + {"Monaco", "Monaco", "MC", "MCO", "492"}, + {"Mongolia", "Mongolie (la)", "MN", "MNG", "496"}, + {"Moldova (the Republic of)", "Moldova , République de", "MD", "MDA", "498"}, + {"Montenegro", "Monténégro (le)", "ME", "MNE", "499"}, + {"Montserrat", "Montserrat", "MS", "MSR", "500"}, + {"Morocco", "Maroc (le)", "MA", "MAR", "504"}, + {"Mozambique", "Mozambique (le)", "MZ", "MOZ", "508"}, + {"Oman", "Oman", "OM", "OMN", "512"}, + {"Namibia", "Namibie (la)", "NA", "NAM", "516"}, + {"Nauru", "Nauru", "NR", "NRU", "520"}, + {"Nepal", "Népal (le)", "NP", "NPL", "524"}, + {"Netherlands (the)", "Pays-Bas (les)", "NL", "NLD", "528"}, + {"Curaçao", "Curaçao", "CW", "CUW", "531"}, + {"Aruba", "Aruba", "AW", "ABW", "533"}, + {"Sint Maarten (Dutch part)", "Saint-Martin (partie néerlandaise)", "SX", "SXM", "534"}, + {"Bonaire, Sint Eustatius and Saba", "Bonaire, Saint-Eustache et Saba", "BQ", "BES", "535"}, + {"New Caledonia", "Nouvelle-Calédonie (la)", "NC", "NCL", "540"}, + {"Vanuatu", "Vanuatu (le)", "VU", "VUT", "548"}, + {"New Zealand", "Nouvelle-Zélande (la)", "NZ", "NZL", "554"}, + {"Nicaragua", "Nicaragua (le)", "NI", "NIC", "558"}, + {"Niger (the)", "Niger (le)", "NE", "NER", "562"}, + {"Nigeria", "Nigéria (le)", "NG", "NGA", "566"}, + {"Niue", "Niue", "NU", "NIU", "570"}, + {"Norfolk Island", "Norfolk (l'Île)", "NF", "NFK", "574"}, + {"Norway", "Norvège (la)", "NO", "NOR", "578"}, + {"Northern Mariana Islands (the)", "Mariannes du Nord (les Îles)", "MP", "MNP", "580"}, + {"United States Minor Outlying Islands (the)", "Îles mineures éloignées des États-Unis (les)", "UM", "UMI", "581"}, + {"Micronesia (Federated States of)", "Micronésie (États fédérés de)", "FM", "FSM", "583"}, + {"Marshall Islands (the)", "Marshall (Îles)", "MH", "MHL", "584"}, + {"Palau", "Palaos (les)", "PW", "PLW", "585"}, + {"Pakistan", "Pakistan (le)", "PK", "PAK", "586"}, + {"Panama", "Panama (le)", "PA", "PAN", "591"}, + {"Papua New Guinea", "Papouasie-Nouvelle-Guinée (la)", "PG", "PNG", "598"}, + {"Paraguay", "Paraguay (le)", "PY", "PRY", "600"}, + {"Peru", "Pérou (le)", "PE", "PER", "604"}, + {"Philippines (the)", "Philippines (les)", "PH", "PHL", "608"}, + {"Pitcairn", "Pitcairn", "PN", "PCN", "612"}, + {"Poland", "Pologne (la)", "PL", "POL", "616"}, + {"Portugal", "Portugal (le)", "PT", "PRT", "620"}, + {"Guinea-Bissau", "Guinée-Bissau (la)", "GW", "GNB", "624"}, + {"Timor-Leste", "Timor-Leste (le)", "TL", "TLS", "626"}, + {"Puerto Rico", "Porto Rico", "PR", "PRI", "630"}, + {"Qatar", "Qatar (le)", "QA", "QAT", "634"}, + {"Réunion", "Réunion (La)", "RE", "REU", "638"}, + {"Romania", "Roumanie (la)", "RO", "ROU", "642"}, + {"Russian Federation (the)", "Russie (la Fédération de)", "RU", "RUS", "643"}, + {"Rwanda", "Rwanda (le)", "RW", "RWA", "646"}, + {"Saint Barthélemy", "Saint-Barthélemy", "BL", "BLM", "652"}, + {"Saint Helena, Ascension and Tristan da Cunha", "Sainte-Hélène, Ascension et Tristan da Cunha", "SH", "SHN", "654"}, + {"Saint Kitts and Nevis", "Saint-Kitts-et-Nevis", "KN", "KNA", "659"}, + {"Anguilla", "Anguilla", "AI", "AIA", "660"}, + {"Saint Lucia", "Sainte-Lucie", "LC", "LCA", "662"}, + {"Saint Martin (French part)", "Saint-Martin (partie française)", "MF", "MAF", "663"}, + {"Saint Pierre and Miquelon", "Saint-Pierre-et-Miquelon", "PM", "SPM", "666"}, + {"Saint Vincent and the Grenadines", "Saint-Vincent-et-les Grenadines", "VC", "VCT", "670"}, + {"San Marino", "Saint-Marin", "SM", "SMR", "674"}, + {"Sao Tome and Principe", "Sao Tomé-et-Principe", "ST", "STP", "678"}, + {"Saudi Arabia", "Arabie saoudite (l')", "SA", "SAU", "682"}, + {"Senegal", "Sénégal (le)", "SN", "SEN", "686"}, + {"Serbia", "Serbie (la)", "RS", "SRB", "688"}, + {"Seychelles", "Seychelles (les)", "SC", "SYC", "690"}, + {"Sierra Leone", "Sierra Leone (la)", "SL", "SLE", "694"}, + {"Singapore", "Singapour", "SG", "SGP", "702"}, + {"Slovakia", "Slovaquie (la)", "SK", "SVK", "703"}, + {"Viet Nam", "Viet Nam (le)", "VN", "VNM", "704"}, + {"Slovenia", "Slovénie (la)", "SI", "SVN", "705"}, + {"Somalia", "Somalie (la)", "SO", "SOM", "706"}, + {"South Africa", "Afrique du Sud (l')", "ZA", "ZAF", "710"}, + {"Zimbabwe", "Zimbabwe (le)", "ZW", "ZWE", "716"}, + {"Spain", "Espagne (l')", "ES", "ESP", "724"}, + {"South Sudan", "Soudan du Sud (le)", "SS", "SSD", "728"}, + {"Sudan (the)", "Soudan (le)", "SD", "SDN", "729"}, + {"Western Sahara*", "Sahara occidental (le)*", "EH", "ESH", "732"}, + {"Suriname", "Suriname (le)", "SR", "SUR", "740"}, + {"Svalbard and Jan Mayen", "Svalbard et l'Île Jan Mayen (le)", "SJ", "SJM", "744"}, + {"Swaziland", "Swaziland (le)", "SZ", "SWZ", "748"}, + {"Sweden", "Suède (la)", "SE", "SWE", "752"}, + {"Switzerland", "Suisse (la)", "CH", "CHE", "756"}, + {"Syrian Arab Republic", "République arabe syrienne (la)", "SY", "SYR", "760"}, + {"Tajikistan", "Tadjikistan (le)", "TJ", "TJK", "762"}, + {"Thailand", "Thaïlande (la)", "TH", "THA", "764"}, + {"Togo", "Togo (le)", "TG", "TGO", "768"}, + {"Tokelau", "Tokelau (les)", "TK", "TKL", "772"}, + {"Tonga", "Tonga (les)", "TO", "TON", "776"}, + {"Trinidad and Tobago", "Trinité-et-Tobago (la)", "TT", "TTO", "780"}, + {"United Arab Emirates (the)", "Émirats arabes unis (les)", "AE", "ARE", "784"}, + {"Tunisia", "Tunisie (la)", "TN", "TUN", "788"}, + {"Turkey", "Turquie (la)", "TR", "TUR", "792"}, + {"Turkmenistan", "Turkménistan (le)", "TM", "TKM", "795"}, + {"Turks and Caicos Islands (the)", "Turks-et-Caïcos (les Îles)", "TC", "TCA", "796"}, + {"Tuvalu", "Tuvalu (les)", "TV", "TUV", "798"}, + {"Uganda", "Ouganda (l')", "UG", "UGA", "800"}, + {"Ukraine", "Ukraine (l')", "UA", "UKR", "804"}, + {"Macedonia (the former Yugoslav Republic of)", "Macédoine (l'ex‑République yougoslave de)", "MK", "MKD", "807"}, + {"Egypt", "Égypte (l')", "EG", "EGY", "818"}, + {"United Kingdom of Great Britain and Northern Ireland (the)", "Royaume-Uni de Grande-Bretagne et d'Irlande du Nord (le)", "GB", "GBR", "826"}, + {"Guernsey", "Guernesey", "GG", "GGY", "831"}, + {"Jersey", "Jersey", "JE", "JEY", "832"}, + {"Isle of Man", "Île de Man", "IM", "IMN", "833"}, + {"Tanzania, United Republic of", "Tanzanie, République-Unie de", "TZ", "TZA", "834"}, + {"United States of America (the)", "États-Unis d'Amérique (les)", "US", "USA", "840"}, + {"Virgin Islands (U.S.)", "Vierges des États-Unis (les Îles)", "VI", "VIR", "850"}, + {"Burkina Faso", "Burkina Faso (le)", "BF", "BFA", "854"}, + {"Uruguay", "Uruguay (l')", "UY", "URY", "858"}, + {"Uzbekistan", "Ouzbékistan (l')", "UZ", "UZB", "860"}, + {"Venezuela (Bolivarian Republic of)", "Venezuela (République bolivarienne du)", "VE", "VEN", "862"}, + {"Wallis and Futuna", "Wallis-et-Futuna", "WF", "WLF", "876"}, + {"Samoa", "Samoa (le)", "WS", "WSM", "882"}, + {"Yemen", "Yémen (le)", "YE", "YEM", "887"}, + {"Zambia", "Zambie (la)", "ZM", "ZMB", "894"}, +} + +// ISO4217List is the list of ISO currency codes +var ISO4217List = []string{ + "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", + "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", + "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK", + "DJF", "DKK", "DOP", "DZD", + "EGP", "ERN", "ETB", "EUR", + "FJD", "FKP", + "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", + "HKD", "HNL", "HRK", "HTG", "HUF", + "IDR", "ILS", "INR", "IQD", "IRR", "ISK", + "JMD", "JOD", "JPY", + "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", + "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", + "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", + "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", + "OMR", + "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", + "QAR", + "RON", "RSD", "RUB", "RWF", + "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "SSP", "STD", "SVC", "SYP", "SZL", + "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", + "UAH", "UGX", "USD", "USN", "UYI", "UYU", "UZS", + "VEF", "VND", "VUV", + "WST", + "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", + "YER", + "ZAR", "ZMW", "ZWL", +} + +// ISO693Entry stores ISO language codes +type ISO693Entry struct { + Alpha3bCode string + Alpha2Code string + English string +} + +//ISO693List based on http://data.okfn.org/data/core/language-codes/r/language-codes-3b2.json +var ISO693List = []ISO693Entry{ + {Alpha3bCode: "aar", Alpha2Code: "aa", English: "Afar"}, + {Alpha3bCode: "abk", Alpha2Code: "ab", English: "Abkhazian"}, + {Alpha3bCode: "afr", Alpha2Code: "af", English: "Afrikaans"}, + {Alpha3bCode: "aka", Alpha2Code: "ak", English: "Akan"}, + {Alpha3bCode: "alb", Alpha2Code: "sq", English: "Albanian"}, + {Alpha3bCode: "amh", Alpha2Code: "am", English: "Amharic"}, + {Alpha3bCode: "ara", Alpha2Code: "ar", English: "Arabic"}, + {Alpha3bCode: "arg", Alpha2Code: "an", English: "Aragonese"}, + {Alpha3bCode: "arm", Alpha2Code: "hy", English: "Armenian"}, + {Alpha3bCode: "asm", Alpha2Code: "as", English: "Assamese"}, + {Alpha3bCode: "ava", Alpha2Code: "av", English: "Avaric"}, + {Alpha3bCode: "ave", Alpha2Code: "ae", English: "Avestan"}, + {Alpha3bCode: "aym", Alpha2Code: "ay", English: "Aymara"}, + {Alpha3bCode: "aze", Alpha2Code: "az", English: "Azerbaijani"}, + {Alpha3bCode: "bak", Alpha2Code: "ba", English: "Bashkir"}, + {Alpha3bCode: "bam", Alpha2Code: "bm", English: "Bambara"}, + {Alpha3bCode: "baq", Alpha2Code: "eu", English: "Basque"}, + {Alpha3bCode: "bel", Alpha2Code: "be", English: "Belarusian"}, + {Alpha3bCode: "ben", Alpha2Code: "bn", English: "Bengali"}, + {Alpha3bCode: "bih", Alpha2Code: "bh", English: "Bihari languages"}, + {Alpha3bCode: "bis", Alpha2Code: "bi", English: "Bislama"}, + {Alpha3bCode: "bos", Alpha2Code: "bs", English: "Bosnian"}, + {Alpha3bCode: "bre", Alpha2Code: "br", English: "Breton"}, + {Alpha3bCode: "bul", Alpha2Code: "bg", English: "Bulgarian"}, + {Alpha3bCode: "bur", Alpha2Code: "my", English: "Burmese"}, + {Alpha3bCode: "cat", Alpha2Code: "ca", English: "Catalan; Valencian"}, + {Alpha3bCode: "cha", Alpha2Code: "ch", English: "Chamorro"}, + {Alpha3bCode: "che", Alpha2Code: "ce", English: "Chechen"}, + {Alpha3bCode: "chi", Alpha2Code: "zh", English: "Chinese"}, + {Alpha3bCode: "chu", Alpha2Code: "cu", English: "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic"}, + {Alpha3bCode: "chv", Alpha2Code: "cv", English: "Chuvash"}, + {Alpha3bCode: "cor", Alpha2Code: "kw", English: "Cornish"}, + {Alpha3bCode: "cos", Alpha2Code: "co", English: "Corsican"}, + {Alpha3bCode: "cre", Alpha2Code: "cr", English: "Cree"}, + {Alpha3bCode: "cze", Alpha2Code: "cs", English: "Czech"}, + {Alpha3bCode: "dan", Alpha2Code: "da", English: "Danish"}, + {Alpha3bCode: "div", Alpha2Code: "dv", English: "Divehi; Dhivehi; Maldivian"}, + {Alpha3bCode: "dut", Alpha2Code: "nl", English: "Dutch; Flemish"}, + {Alpha3bCode: "dzo", Alpha2Code: "dz", English: "Dzongkha"}, + {Alpha3bCode: "eng", Alpha2Code: "en", English: "English"}, + {Alpha3bCode: "epo", Alpha2Code: "eo", English: "Esperanto"}, + {Alpha3bCode: "est", Alpha2Code: "et", English: "Estonian"}, + {Alpha3bCode: "ewe", Alpha2Code: "ee", English: "Ewe"}, + {Alpha3bCode: "fao", Alpha2Code: "fo", English: "Faroese"}, + {Alpha3bCode: "fij", Alpha2Code: "fj", English: "Fijian"}, + {Alpha3bCode: "fin", Alpha2Code: "fi", English: "Finnish"}, + {Alpha3bCode: "fre", Alpha2Code: "fr", English: "French"}, + {Alpha3bCode: "fry", Alpha2Code: "fy", English: "Western Frisian"}, + {Alpha3bCode: "ful", Alpha2Code: "ff", English: "Fulah"}, + {Alpha3bCode: "geo", Alpha2Code: "ka", English: "Georgian"}, + {Alpha3bCode: "ger", Alpha2Code: "de", English: "German"}, + {Alpha3bCode: "gla", Alpha2Code: "gd", English: "Gaelic; Scottish Gaelic"}, + {Alpha3bCode: "gle", Alpha2Code: "ga", English: "Irish"}, + {Alpha3bCode: "glg", Alpha2Code: "gl", English: "Galician"}, + {Alpha3bCode: "glv", Alpha2Code: "gv", English: "Manx"}, + {Alpha3bCode: "gre", Alpha2Code: "el", English: "Greek, Modern (1453-)"}, + {Alpha3bCode: "grn", Alpha2Code: "gn", English: "Guarani"}, + {Alpha3bCode: "guj", Alpha2Code: "gu", English: "Gujarati"}, + {Alpha3bCode: "hat", Alpha2Code: "ht", English: "Haitian; Haitian Creole"}, + {Alpha3bCode: "hau", Alpha2Code: "ha", English: "Hausa"}, + {Alpha3bCode: "heb", Alpha2Code: "he", English: "Hebrew"}, + {Alpha3bCode: "her", Alpha2Code: "hz", English: "Herero"}, + {Alpha3bCode: "hin", Alpha2Code: "hi", English: "Hindi"}, + {Alpha3bCode: "hmo", Alpha2Code: "ho", English: "Hiri Motu"}, + {Alpha3bCode: "hrv", Alpha2Code: "hr", English: "Croatian"}, + {Alpha3bCode: "hun", Alpha2Code: "hu", English: "Hungarian"}, + {Alpha3bCode: "ibo", Alpha2Code: "ig", English: "Igbo"}, + {Alpha3bCode: "ice", Alpha2Code: "is", English: "Icelandic"}, + {Alpha3bCode: "ido", Alpha2Code: "io", English: "Ido"}, + {Alpha3bCode: "iii", Alpha2Code: "ii", English: "Sichuan Yi; Nuosu"}, + {Alpha3bCode: "iku", Alpha2Code: "iu", English: "Inuktitut"}, + {Alpha3bCode: "ile", Alpha2Code: "ie", English: "Interlingue; Occidental"}, + {Alpha3bCode: "ina", Alpha2Code: "ia", English: "Interlingua (International Auxiliary Language Association)"}, + {Alpha3bCode: "ind", Alpha2Code: "id", English: "Indonesian"}, + {Alpha3bCode: "ipk", Alpha2Code: "ik", English: "Inupiaq"}, + {Alpha3bCode: "ita", Alpha2Code: "it", English: "Italian"}, + {Alpha3bCode: "jav", Alpha2Code: "jv", English: "Javanese"}, + {Alpha3bCode: "jpn", Alpha2Code: "ja", English: "Japanese"}, + {Alpha3bCode: "kal", Alpha2Code: "kl", English: "Kalaallisut; Greenlandic"}, + {Alpha3bCode: "kan", Alpha2Code: "kn", English: "Kannada"}, + {Alpha3bCode: "kas", Alpha2Code: "ks", English: "Kashmiri"}, + {Alpha3bCode: "kau", Alpha2Code: "kr", English: "Kanuri"}, + {Alpha3bCode: "kaz", Alpha2Code: "kk", English: "Kazakh"}, + {Alpha3bCode: "khm", Alpha2Code: "km", English: "Central Khmer"}, + {Alpha3bCode: "kik", Alpha2Code: "ki", English: "Kikuyu; Gikuyu"}, + {Alpha3bCode: "kin", Alpha2Code: "rw", English: "Kinyarwanda"}, + {Alpha3bCode: "kir", Alpha2Code: "ky", English: "Kirghiz; Kyrgyz"}, + {Alpha3bCode: "kom", Alpha2Code: "kv", English: "Komi"}, + {Alpha3bCode: "kon", Alpha2Code: "kg", English: "Kongo"}, + {Alpha3bCode: "kor", Alpha2Code: "ko", English: "Korean"}, + {Alpha3bCode: "kua", Alpha2Code: "kj", English: "Kuanyama; Kwanyama"}, + {Alpha3bCode: "kur", Alpha2Code: "ku", English: "Kurdish"}, + {Alpha3bCode: "lao", Alpha2Code: "lo", English: "Lao"}, + {Alpha3bCode: "lat", Alpha2Code: "la", English: "Latin"}, + {Alpha3bCode: "lav", Alpha2Code: "lv", English: "Latvian"}, + {Alpha3bCode: "lim", Alpha2Code: "li", English: "Limburgan; Limburger; Limburgish"}, + {Alpha3bCode: "lin", Alpha2Code: "ln", English: "Lingala"}, + {Alpha3bCode: "lit", Alpha2Code: "lt", English: "Lithuanian"}, + {Alpha3bCode: "ltz", Alpha2Code: "lb", English: "Luxembourgish; Letzeburgesch"}, + {Alpha3bCode: "lub", Alpha2Code: "lu", English: "Luba-Katanga"}, + {Alpha3bCode: "lug", Alpha2Code: "lg", English: "Ganda"}, + {Alpha3bCode: "mac", Alpha2Code: "mk", English: "Macedonian"}, + {Alpha3bCode: "mah", Alpha2Code: "mh", English: "Marshallese"}, + {Alpha3bCode: "mal", Alpha2Code: "ml", English: "Malayalam"}, + {Alpha3bCode: "mao", Alpha2Code: "mi", English: "Maori"}, + {Alpha3bCode: "mar", Alpha2Code: "mr", English: "Marathi"}, + {Alpha3bCode: "may", Alpha2Code: "ms", English: "Malay"}, + {Alpha3bCode: "mlg", Alpha2Code: "mg", English: "Malagasy"}, + {Alpha3bCode: "mlt", Alpha2Code: "mt", English: "Maltese"}, + {Alpha3bCode: "mon", Alpha2Code: "mn", English: "Mongolian"}, + {Alpha3bCode: "nau", Alpha2Code: "na", English: "Nauru"}, + {Alpha3bCode: "nav", Alpha2Code: "nv", English: "Navajo; Navaho"}, + {Alpha3bCode: "nbl", Alpha2Code: "nr", English: "Ndebele, South; South Ndebele"}, + {Alpha3bCode: "nde", Alpha2Code: "nd", English: "Ndebele, North; North Ndebele"}, + {Alpha3bCode: "ndo", Alpha2Code: "ng", English: "Ndonga"}, + {Alpha3bCode: "nep", Alpha2Code: "ne", English: "Nepali"}, + {Alpha3bCode: "nno", Alpha2Code: "nn", English: "Norwegian Nynorsk; Nynorsk, Norwegian"}, + {Alpha3bCode: "nob", Alpha2Code: "nb", English: "Bokmål, Norwegian; Norwegian Bokmål"}, + {Alpha3bCode: "nor", Alpha2Code: "no", English: "Norwegian"}, + {Alpha3bCode: "nya", Alpha2Code: "ny", English: "Chichewa; Chewa; Nyanja"}, + {Alpha3bCode: "oci", Alpha2Code: "oc", English: "Occitan (post 1500); Provençal"}, + {Alpha3bCode: "oji", Alpha2Code: "oj", English: "Ojibwa"}, + {Alpha3bCode: "ori", Alpha2Code: "or", English: "Oriya"}, + {Alpha3bCode: "orm", Alpha2Code: "om", English: "Oromo"}, + {Alpha3bCode: "oss", Alpha2Code: "os", English: "Ossetian; Ossetic"}, + {Alpha3bCode: "pan", Alpha2Code: "pa", English: "Panjabi; Punjabi"}, + {Alpha3bCode: "per", Alpha2Code: "fa", English: "Persian"}, + {Alpha3bCode: "pli", Alpha2Code: "pi", English: "Pali"}, + {Alpha3bCode: "pol", Alpha2Code: "pl", English: "Polish"}, + {Alpha3bCode: "por", Alpha2Code: "pt", English: "Portuguese"}, + {Alpha3bCode: "pus", Alpha2Code: "ps", English: "Pushto; Pashto"}, + {Alpha3bCode: "que", Alpha2Code: "qu", English: "Quechua"}, + {Alpha3bCode: "roh", Alpha2Code: "rm", English: "Romansh"}, + {Alpha3bCode: "rum", Alpha2Code: "ro", English: "Romanian; Moldavian; Moldovan"}, + {Alpha3bCode: "run", Alpha2Code: "rn", English: "Rundi"}, + {Alpha3bCode: "rus", Alpha2Code: "ru", English: "Russian"}, + {Alpha3bCode: "sag", Alpha2Code: "sg", English: "Sango"}, + {Alpha3bCode: "san", Alpha2Code: "sa", English: "Sanskrit"}, + {Alpha3bCode: "sin", Alpha2Code: "si", English: "Sinhala; Sinhalese"}, + {Alpha3bCode: "slo", Alpha2Code: "sk", English: "Slovak"}, + {Alpha3bCode: "slv", Alpha2Code: "sl", English: "Slovenian"}, + {Alpha3bCode: "sme", Alpha2Code: "se", English: "Northern Sami"}, + {Alpha3bCode: "smo", Alpha2Code: "sm", English: "Samoan"}, + {Alpha3bCode: "sna", Alpha2Code: "sn", English: "Shona"}, + {Alpha3bCode: "snd", Alpha2Code: "sd", English: "Sindhi"}, + {Alpha3bCode: "som", Alpha2Code: "so", English: "Somali"}, + {Alpha3bCode: "sot", Alpha2Code: "st", English: "Sotho, Southern"}, + {Alpha3bCode: "spa", Alpha2Code: "es", English: "Spanish; Castilian"}, + {Alpha3bCode: "srd", Alpha2Code: "sc", English: "Sardinian"}, + {Alpha3bCode: "srp", Alpha2Code: "sr", English: "Serbian"}, + {Alpha3bCode: "ssw", Alpha2Code: "ss", English: "Swati"}, + {Alpha3bCode: "sun", Alpha2Code: "su", English: "Sundanese"}, + {Alpha3bCode: "swa", Alpha2Code: "sw", English: "Swahili"}, + {Alpha3bCode: "swe", Alpha2Code: "sv", English: "Swedish"}, + {Alpha3bCode: "tah", Alpha2Code: "ty", English: "Tahitian"}, + {Alpha3bCode: "tam", Alpha2Code: "ta", English: "Tamil"}, + {Alpha3bCode: "tat", Alpha2Code: "tt", English: "Tatar"}, + {Alpha3bCode: "tel", Alpha2Code: "te", English: "Telugu"}, + {Alpha3bCode: "tgk", Alpha2Code: "tg", English: "Tajik"}, + {Alpha3bCode: "tgl", Alpha2Code: "tl", English: "Tagalog"}, + {Alpha3bCode: "tha", Alpha2Code: "th", English: "Thai"}, + {Alpha3bCode: "tib", Alpha2Code: "bo", English: "Tibetan"}, + {Alpha3bCode: "tir", Alpha2Code: "ti", English: "Tigrinya"}, + {Alpha3bCode: "ton", Alpha2Code: "to", English: "Tonga (Tonga Islands)"}, + {Alpha3bCode: "tsn", Alpha2Code: "tn", English: "Tswana"}, + {Alpha3bCode: "tso", Alpha2Code: "ts", English: "Tsonga"}, + {Alpha3bCode: "tuk", Alpha2Code: "tk", English: "Turkmen"}, + {Alpha3bCode: "tur", Alpha2Code: "tr", English: "Turkish"}, + {Alpha3bCode: "twi", Alpha2Code: "tw", English: "Twi"}, + {Alpha3bCode: "uig", Alpha2Code: "ug", English: "Uighur; Uyghur"}, + {Alpha3bCode: "ukr", Alpha2Code: "uk", English: "Ukrainian"}, + {Alpha3bCode: "urd", Alpha2Code: "ur", English: "Urdu"}, + {Alpha3bCode: "uzb", Alpha2Code: "uz", English: "Uzbek"}, + {Alpha3bCode: "ven", Alpha2Code: "ve", English: "Venda"}, + {Alpha3bCode: "vie", Alpha2Code: "vi", English: "Vietnamese"}, + {Alpha3bCode: "vol", Alpha2Code: "vo", English: "Volapük"}, + {Alpha3bCode: "wel", Alpha2Code: "cy", English: "Welsh"}, + {Alpha3bCode: "wln", Alpha2Code: "wa", English: "Walloon"}, + {Alpha3bCode: "wol", Alpha2Code: "wo", English: "Wolof"}, + {Alpha3bCode: "xho", Alpha2Code: "xh", English: "Xhosa"}, + {Alpha3bCode: "yid", Alpha2Code: "yi", English: "Yiddish"}, + {Alpha3bCode: "yor", Alpha2Code: "yo", English: "Yoruba"}, + {Alpha3bCode: "zha", Alpha2Code: "za", English: "Zhuang; Chuang"}, + {Alpha3bCode: "zul", Alpha2Code: "zu", English: "Zulu"}, +} diff --git a/vendor/github.com/asaskevich/govalidator/utils.go b/vendor/github.com/asaskevich/govalidator/utils.go new file mode 100644 index 000000000..6a8871c1c --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/utils.go @@ -0,0 +1,264 @@ +package govalidator + +import ( + "errors" + "fmt" + "html" + "math" + "path" + "regexp" + "strings" + "unicode" + "unicode/utf8" +) + +// Contains check if the string contains the substring. +func Contains(str, substring string) bool { + return strings.Contains(str, substring) +} + +// Matches check if string matches the pattern (pattern is regular expression) +// In case of error return false +func Matches(str, pattern string) bool { + match, _ := regexp.MatchString(pattern, str) + return match +} + +// LeftTrim trim characters from the left-side of the input. +// If second argument is empty, it's will be remove leading spaces. +func LeftTrim(str, chars string) string { + if chars == "" { + return strings.TrimLeftFunc(str, unicode.IsSpace) + } + r, _ := regexp.Compile("^[" + chars + "]+") + return r.ReplaceAllString(str, "") +} + +// RightTrim trim characters from the right-side of the input. +// If second argument is empty, it's will be remove spaces. +func RightTrim(str, chars string) string { + if chars == "" { + return strings.TrimRightFunc(str, unicode.IsSpace) + } + r, _ := regexp.Compile("[" + chars + "]+$") + return r.ReplaceAllString(str, "") +} + +// Trim trim characters from both sides of the input. +// If second argument is empty, it's will be remove spaces. +func Trim(str, chars string) string { + return LeftTrim(RightTrim(str, chars), chars) +} + +// WhiteList remove characters that do not appear in the whitelist. +func WhiteList(str, chars string) string { + pattern := "[^" + chars + "]+" + r, _ := regexp.Compile(pattern) + return r.ReplaceAllString(str, "") +} + +// BlackList remove characters that appear in the blacklist. +func BlackList(str, chars string) string { + pattern := "[" + chars + "]+" + r, _ := regexp.Compile(pattern) + return r.ReplaceAllString(str, "") +} + +// StripLow remove characters with a numerical value < 32 and 127, mostly control characters. +// If keep_new_lines is true, newline characters are preserved (\n and \r, hex 0xA and 0xD). +func StripLow(str string, keepNewLines bool) string { + chars := "" + if keepNewLines { + chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F" + } else { + chars = "\x00-\x1F\x7F" + } + return BlackList(str, chars) +} + +// ReplacePattern replace regular expression pattern in string +func ReplacePattern(str, pattern, replace string) string { + r, _ := regexp.Compile(pattern) + return r.ReplaceAllString(str, replace) +} + +// Escape replace <, >, & and " with HTML entities. +var Escape = html.EscapeString + +func addSegment(inrune, segment []rune) []rune { + if len(segment) == 0 { + return inrune + } + if len(inrune) != 0 { + inrune = append(inrune, '_') + } + inrune = append(inrune, segment...) + return inrune +} + +// UnderscoreToCamelCase converts from underscore separated form to camel case form. +// Ex.: my_func => MyFunc +func UnderscoreToCamelCase(s string) string { + return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1) +} + +// CamelCaseToUnderscore converts from camel case form to underscore separated form. +// Ex.: MyFunc => my_func +func CamelCaseToUnderscore(str string) string { + var output []rune + var segment []rune + for _, r := range str { + + // not treat number as separate segment + if !unicode.IsLower(r) && string(r) != "_" && !unicode.IsNumber(r) { + output = addSegment(output, segment) + segment = nil + } + segment = append(segment, unicode.ToLower(r)) + } + output = addSegment(output, segment) + return string(output) +} + +// Reverse return reversed string +func Reverse(s string) string { + r := []rune(s) + for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 { + r[i], r[j] = r[j], r[i] + } + return string(r) +} + +// GetLines split string by "\n" and return array of lines +func GetLines(s string) []string { + return strings.Split(s, "\n") +} + +// GetLine return specified line of multiline string +func GetLine(s string, index int) (string, error) { + lines := GetLines(s) + if index < 0 || index >= len(lines) { + return "", errors.New("line index out of bounds") + } + return lines[index], nil +} + +// RemoveTags remove all tags from HTML string +func RemoveTags(s string) string { + return ReplacePattern(s, "<[^>]*>", "") +} + +// SafeFileName return safe string that can be used in file names +func SafeFileName(str string) string { + name := strings.ToLower(str) + name = path.Clean(path.Base(name)) + name = strings.Trim(name, " ") + separators, err := regexp.Compile(`[ &_=+:]`) + if err == nil { + name = separators.ReplaceAllString(name, "-") + } + legal, err := regexp.Compile(`[^[:alnum:]-.]`) + if err == nil { + name = legal.ReplaceAllString(name, "") + } + for strings.Contains(name, "--") { + name = strings.Replace(name, "--", "-", -1) + } + return name +} + +// NormalizeEmail canonicalize an email address. +// The local part of the email address is lowercased for all domains; the hostname is always lowercased and +// the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail). +// Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and +// are stripped of tags (e.g. some.one+tag@gmail.com becomes someone@gmail.com) and all @googlemail.com addresses are +// normalized to @gmail.com. +func NormalizeEmail(str string) (string, error) { + if !IsEmail(str) { + return "", fmt.Errorf("%s is not an email", str) + } + parts := strings.Split(str, "@") + parts[0] = strings.ToLower(parts[0]) + parts[1] = strings.ToLower(parts[1]) + if parts[1] == "gmail.com" || parts[1] == "googlemail.com" { + parts[1] = "gmail.com" + parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0] + } + return strings.Join(parts, "@"), nil +} + +// Truncate a string to the closest length without breaking words. +func Truncate(str string, length int, ending string) string { + var aftstr, befstr string + if len(str) > length { + words := strings.Fields(str) + before, present := 0, 0 + for i := range words { + befstr = aftstr + before = present + aftstr = aftstr + words[i] + " " + present = len(aftstr) + if present > length && i != 0 { + if (length - before) < (present - length) { + return Trim(befstr, " /\\.,\"'#!?&@+-") + ending + } + return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending + } + } + } + + return str +} + +// PadLeft pad left side of string if size of string is less then indicated pad length +func PadLeft(str string, padStr string, padLen int) string { + return buildPadStr(str, padStr, padLen, true, false) +} + +// PadRight pad right side of string if size of string is less then indicated pad length +func PadRight(str string, padStr string, padLen int) string { + return buildPadStr(str, padStr, padLen, false, true) +} + +// PadBoth pad sides of string if size of string is less then indicated pad length +func PadBoth(str string, padStr string, padLen int) string { + return buildPadStr(str, padStr, padLen, true, true) +} + +// PadString either left, right or both sides, not the padding string can be unicode and more then one +// character +func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string { + + // When padded length is less then the current string size + if padLen < utf8.RuneCountInString(str) { + return str + } + + padLen -= utf8.RuneCountInString(str) + + targetLen := padLen + + targetLenLeft := targetLen + targetLenRight := targetLen + if padLeft && padRight { + targetLenLeft = padLen / 2 + targetLenRight = padLen - targetLenLeft + } + + strToRepeatLen := utf8.RuneCountInString(padStr) + + repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen))) + repeatedString := strings.Repeat(padStr, repeatTimes) + + leftSide := "" + if padLeft { + leftSide = repeatedString[0:targetLenLeft] + } + + rightSide := "" + if padRight { + rightSide = repeatedString[0:targetLenRight] + } + + return leftSide + str + rightSide +} diff --git a/vendor/github.com/asaskevich/govalidator/validator.go b/vendor/github.com/asaskevich/govalidator/validator.go new file mode 100644 index 000000000..f49431401 --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/validator.go @@ -0,0 +1,1220 @@ +// Package govalidator is package of validators and sanitizers for strings, structs and collections. +package govalidator + +import ( + "bytes" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "fmt" + "io/ioutil" + "net" + "net/url" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" +) + +var ( + fieldsRequiredByDefault bool + notNumberRegexp = regexp.MustCompile("[^0-9]+") + whiteSpacesAndMinus = regexp.MustCompile("[\\s-]+") + paramsRegexp = regexp.MustCompile("\\(.*\\)$") +) + +const maxURLRuneCount = 2083 +const minURLRuneCount = 3 +const RF3339WithoutZone = "2006-01-02T15:04:05" + +// SetFieldsRequiredByDefault causes validation to fail when struct fields +// do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). +// This struct definition will fail govalidator.ValidateStruct() (and the field values do not matter): +// type exampleStruct struct { +// Name string `` +// Email string `valid:"email"` +// This, however, will only fail when Email is empty or an invalid email address: +// type exampleStruct2 struct { +// Name string `valid:"-"` +// Email string `valid:"email"` +// Lastly, this will only fail when Email is an invalid email address but not when it's empty: +// type exampleStruct2 struct { +// Name string `valid:"-"` +// Email string `valid:"email,optional"` +func SetFieldsRequiredByDefault(value bool) { + fieldsRequiredByDefault = value +} + +// IsEmail check if the string is an email. +func IsEmail(str string) bool { + // TODO uppercase letters are not supported + return rxEmail.MatchString(str) +} + +// IsExistingEmail check if the string is an email of existing domain +func IsExistingEmail(email string) bool { + + if len(email) < 6 || len(email) > 254 { + return false + } + at := strings.LastIndex(email, "@") + if at <= 0 || at > len(email)-3 { + return false + } + user := email[:at] + host := email[at+1:] + if len(user) > 64 { + return false + } + if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) { + return false + } + switch host { + case "localhost", "example.com": + return true + } + if _, err := net.LookupMX(host); err != nil { + if _, err := net.LookupIP(host); err != nil { + return false + } + } + + return true +} + +// IsURL check if the string is an URL. +func IsURL(str string) bool { + if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") { + return false + } + strTemp := str + if strings.Index(str, ":") >= 0 && strings.Index(str, "://") == -1 { + // support no indicated urlscheme but with colon for port number + // http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString + strTemp = "http://" + str + } + u, err := url.Parse(strTemp) + if err != nil { + return false + } + if strings.HasPrefix(u.Host, ".") { + return false + } + if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { + return false + } + return rxURL.MatchString(str) +} + +// IsRequestURL check if the string rawurl, assuming +// it was received in an HTTP request, is a valid +// URL confirm to RFC 3986 +func IsRequestURL(rawurl string) bool { + url, err := url.ParseRequestURI(rawurl) + if err != nil { + return false //Couldn't even parse the rawurl + } + if len(url.Scheme) == 0 { + return false //No Scheme found + } + return true +} + +// IsRequestURI check if the string rawurl, assuming +// it was received in an HTTP request, is an +// absolute URI or an absolute path. +func IsRequestURI(rawurl string) bool { + _, err := url.ParseRequestURI(rawurl) + return err == nil +} + +// IsAlpha check if the string contains only letters (a-zA-Z). Empty string is valid. +func IsAlpha(str string) bool { + if IsNull(str) { + return true + } + return rxAlpha.MatchString(str) +} + +//IsUTFLetter check if the string contains only unicode letter characters. +//Similar to IsAlpha but for all languages. Empty string is valid. +func IsUTFLetter(str string) bool { + if IsNull(str) { + return true + } + + for _, c := range str { + if !unicode.IsLetter(c) { + return false + } + } + return true + +} + +// IsAlphanumeric check if the string contains only letters and numbers. Empty string is valid. +func IsAlphanumeric(str string) bool { + if IsNull(str) { + return true + } + return rxAlphanumeric.MatchString(str) +} + +// IsUTFLetterNumeric check if the string contains only unicode letters and numbers. Empty string is valid. +func IsUTFLetterNumeric(str string) bool { + if IsNull(str) { + return true + } + for _, c := range str { + if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok + return false + } + } + return true + +} + +// IsNumeric check if the string contains only numbers. Empty string is valid. +func IsNumeric(str string) bool { + if IsNull(str) { + return true + } + return rxNumeric.MatchString(str) +} + +// IsUTFNumeric check if the string contains only unicode numbers of any kind. +// Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid. +func IsUTFNumeric(str string) bool { + if IsNull(str) { + return true + } + if strings.IndexAny(str, "+-") > 0 { + return false + } + if len(str) > 1 { + str = strings.TrimPrefix(str, "-") + str = strings.TrimPrefix(str, "+") + } + for _, c := range str { + if unicode.IsNumber(c) == false { //numbers && minus sign are ok + return false + } + } + return true + +} + +// IsUTFDigit check if the string contains only unicode radix-10 decimal digits. Empty string is valid. +func IsUTFDigit(str string) bool { + if IsNull(str) { + return true + } + if strings.IndexAny(str, "+-") > 0 { + return false + } + if len(str) > 1 { + str = strings.TrimPrefix(str, "-") + str = strings.TrimPrefix(str, "+") + } + for _, c := range str { + if !unicode.IsDigit(c) { //digits && minus sign are ok + return false + } + } + return true + +} + +// IsHexadecimal check if the string is a hexadecimal number. +func IsHexadecimal(str string) bool { + return rxHexadecimal.MatchString(str) +} + +// IsHexcolor check if the string is a hexadecimal color. +func IsHexcolor(str string) bool { + return rxHexcolor.MatchString(str) +} + +// IsRGBcolor check if the string is a valid RGB color in form rgb(RRR, GGG, BBB). +func IsRGBcolor(str string) bool { + return rxRGBcolor.MatchString(str) +} + +// IsLowerCase check if the string is lowercase. Empty string is valid. +func IsLowerCase(str string) bool { + if IsNull(str) { + return true + } + return str == strings.ToLower(str) +} + +// IsUpperCase check if the string is uppercase. Empty string is valid. +func IsUpperCase(str string) bool { + if IsNull(str) { + return true + } + return str == strings.ToUpper(str) +} + +// HasLowerCase check if the string contains at least 1 lowercase. Empty string is valid. +func HasLowerCase(str string) bool { + if IsNull(str) { + return true + } + return rxHasLowerCase.MatchString(str) +} + +// HasUpperCase check if the string contians as least 1 uppercase. Empty string is valid. +func HasUpperCase(str string) bool { + if IsNull(str) { + return true + } + return rxHasUpperCase.MatchString(str) +} + +// IsInt check if the string is an integer. Empty string is valid. +func IsInt(str string) bool { + if IsNull(str) { + return true + } + return rxInt.MatchString(str) +} + +// IsFloat check if the string is a float. +func IsFloat(str string) bool { + return str != "" && rxFloat.MatchString(str) +} + +// IsDivisibleBy check if the string is a number that's divisible by another. +// If second argument is not valid integer or zero, it's return false. +// Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero). +func IsDivisibleBy(str, num string) bool { + f, _ := ToFloat(str) + p := int64(f) + q, _ := ToInt(num) + if q == 0 { + return false + } + return (p == 0) || (p%q == 0) +} + +// IsNull check if the string is null. +func IsNull(str string) bool { + return len(str) == 0 +} + +// IsByteLength check if the string's length (in bytes) falls in a range. +func IsByteLength(str string, min, max int) bool { + return len(str) >= min && len(str) <= max +} + +// IsUUIDv3 check if the string is a UUID version 3. +func IsUUIDv3(str string) bool { + return rxUUID3.MatchString(str) +} + +// IsUUIDv4 check if the string is a UUID version 4. +func IsUUIDv4(str string) bool { + return rxUUID4.MatchString(str) +} + +// IsUUIDv5 check if the string is a UUID version 5. +func IsUUIDv5(str string) bool { + return rxUUID5.MatchString(str) +} + +// IsUUID check if the string is a UUID (version 3, 4 or 5). +func IsUUID(str string) bool { + return rxUUID.MatchString(str) +} + +// IsCreditCard check if the string is a credit card. +func IsCreditCard(str string) bool { + sanitized := notNumberRegexp.ReplaceAllString(str, "") + if !rxCreditCard.MatchString(sanitized) { + return false + } + var sum int64 + var digit string + var tmpNum int64 + var shouldDouble bool + for i := len(sanitized) - 1; i >= 0; i-- { + digit = sanitized[i:(i + 1)] + tmpNum, _ = ToInt(digit) + if shouldDouble { + tmpNum *= 2 + if tmpNum >= 10 { + sum += ((tmpNum % 10) + 1) + } else { + sum += tmpNum + } + } else { + sum += tmpNum + } + shouldDouble = !shouldDouble + } + + if sum%10 == 0 { + return true + } + return false +} + +// IsISBN10 check if the string is an ISBN version 10. +func IsISBN10(str string) bool { + return IsISBN(str, 10) +} + +// IsISBN13 check if the string is an ISBN version 13. +func IsISBN13(str string) bool { + return IsISBN(str, 13) +} + +// IsISBN check if the string is an ISBN (version 10 or 13). +// If version value is not equal to 10 or 13, it will be check both variants. +func IsISBN(str string, version int) bool { + sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "") + var checksum int32 + var i int32 + if version == 10 { + if !rxISBN10.MatchString(sanitized) { + return false + } + for i = 0; i < 9; i++ { + checksum += (i + 1) * int32(sanitized[i]-'0') + } + if sanitized[9] == 'X' { + checksum += 10 * 10 + } else { + checksum += 10 * int32(sanitized[9]-'0') + } + if checksum%11 == 0 { + return true + } + return false + } else if version == 13 { + if !rxISBN13.MatchString(sanitized) { + return false + } + factor := []int32{1, 3} + for i = 0; i < 12; i++ { + checksum += factor[i%2] * int32(sanitized[i]-'0') + } + if (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0 { + return true + } + return false + } + return IsISBN(str, 10) || IsISBN(str, 13) +} + +// IsJSON check if the string is valid JSON (note: uses json.Unmarshal). +func IsJSON(str string) bool { + var js json.RawMessage + return json.Unmarshal([]byte(str), &js) == nil +} + +// IsMultibyte check if the string contains one or more multibyte chars. Empty string is valid. +func IsMultibyte(str string) bool { + if IsNull(str) { + return true + } + return rxMultibyte.MatchString(str) +} + +// IsASCII check if the string contains ASCII chars only. Empty string is valid. +func IsASCII(str string) bool { + if IsNull(str) { + return true + } + return rxASCII.MatchString(str) +} + +// IsPrintableASCII check if the string contains printable ASCII chars only. Empty string is valid. +func IsPrintableASCII(str string) bool { + if IsNull(str) { + return true + } + return rxPrintableASCII.MatchString(str) +} + +// IsFullWidth check if the string contains any full-width chars. Empty string is valid. +func IsFullWidth(str string) bool { + if IsNull(str) { + return true + } + return rxFullWidth.MatchString(str) +} + +// IsHalfWidth check if the string contains any half-width chars. Empty string is valid. +func IsHalfWidth(str string) bool { + if IsNull(str) { + return true + } + return rxHalfWidth.MatchString(str) +} + +// IsVariableWidth check if the string contains a mixture of full and half-width chars. Empty string is valid. +func IsVariableWidth(str string) bool { + if IsNull(str) { + return true + } + return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str) +} + +// IsBase64 check if a string is base64 encoded. +func IsBase64(str string) bool { + return rxBase64.MatchString(str) +} + +// IsFilePath check is a string is Win or Unix file path and returns it's type. +func IsFilePath(str string) (bool, int) { + if rxWinPath.MatchString(str) { + //check windows path limit see: + // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath + if len(str[3:]) > 32767 { + return false, Win + } + return true, Win + } else if rxUnixPath.MatchString(str) { + return true, Unix + } + return false, Unknown +} + +// IsDataURI checks if a string is base64 encoded data URI such as an image +func IsDataURI(str string) bool { + dataURI := strings.Split(str, ",") + if !rxDataURI.MatchString(dataURI[0]) { + return false + } + return IsBase64(dataURI[1]) +} + +// IsISO3166Alpha2 checks if a string is valid two-letter country code +func IsISO3166Alpha2(str string) bool { + for _, entry := range ISO3166List { + if str == entry.Alpha2Code { + return true + } + } + return false +} + +// IsISO3166Alpha3 checks if a string is valid three-letter country code +func IsISO3166Alpha3(str string) bool { + for _, entry := range ISO3166List { + if str == entry.Alpha3Code { + return true + } + } + return false +} + +// IsISO693Alpha2 checks if a string is valid two-letter language code +func IsISO693Alpha2(str string) bool { + for _, entry := range ISO693List { + if str == entry.Alpha2Code { + return true + } + } + return false +} + +// IsISO693Alpha3b checks if a string is valid three-letter language code +func IsISO693Alpha3b(str string) bool { + for _, entry := range ISO693List { + if str == entry.Alpha3bCode { + return true + } + } + return false +} + +// IsDNSName will validate the given string as a DNS name +func IsDNSName(str string) bool { + if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 { + // constraints already violated + return false + } + return !IsIP(str) && rxDNSName.MatchString(str) +} + +// IsHash checks if a string is a hash of type algorithm. +// Algorithm is one of ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b'] +func IsHash(str string, algorithm string) bool { + len := "0" + algo := strings.ToLower(algorithm) + + if algo == "crc32" || algo == "crc32b" { + len = "8" + } else if algo == "md5" || algo == "md4" || algo == "ripemd128" || algo == "tiger128" { + len = "32" + } else if algo == "sha1" || algo == "ripemd160" || algo == "tiger160" { + len = "40" + } else if algo == "tiger192" { + len = "48" + } else if algo == "sha256" { + len = "64" + } else if algo == "sha384" { + len = "96" + } else if algo == "sha512" { + len = "128" + } else { + return false + } + + return Matches(str, "^[a-f0-9]{"+len+"}$") +} + +// IsDialString validates the given string for usage with the various Dial() functions +func IsDialString(str string) bool { + + if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) { + return true + } + + return false +} + +// IsIP checks if a string is either IP version 4 or 6. +func IsIP(str string) bool { + return net.ParseIP(str) != nil +} + +// IsPort checks if a string represents a valid port +func IsPort(str string) bool { + if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 { + return true + } + return false +} + +// IsIPv4 check if the string is an IP version 4. +func IsIPv4(str string) bool { + ip := net.ParseIP(str) + return ip != nil && strings.Contains(str, ".") +} + +// IsIPv6 check if the string is an IP version 6. +func IsIPv6(str string) bool { + ip := net.ParseIP(str) + return ip != nil && strings.Contains(str, ":") +} + +// IsCIDR check if the string is an valid CIDR notiation (IPV4 & IPV6) +func IsCIDR(str string) bool { + _, _, err := net.ParseCIDR(str) + return err == nil +} + +// IsMAC check if a string is valid MAC address. +// Possible MAC formats: +// 01:23:45:67:89:ab +// 01:23:45:67:89:ab:cd:ef +// 01-23-45-67-89-ab +// 01-23-45-67-89-ab-cd-ef +// 0123.4567.89ab +// 0123.4567.89ab.cdef +func IsMAC(str string) bool { + _, err := net.ParseMAC(str) + return err == nil +} + +// IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name +func IsHost(str string) bool { + return IsIP(str) || IsDNSName(str) +} + +// IsMongoID check if the string is a valid hex-encoded representation of a MongoDB ObjectId. +func IsMongoID(str string) bool { + return rxHexadecimal.MatchString(str) && (len(str) == 24) +} + +// IsLatitude check if a string is valid latitude. +func IsLatitude(str string) bool { + return rxLatitude.MatchString(str) +} + +// IsLongitude check if a string is valid longitude. +func IsLongitude(str string) bool { + return rxLongitude.MatchString(str) +} + +// IsRsaPublicKey check if a string is valid public key with provided length +func IsRsaPublicKey(str string, keylen int) bool { + bb := bytes.NewBufferString(str) + pemBytes, err := ioutil.ReadAll(bb) + if err != nil { + return false + } + block, _ := pem.Decode(pemBytes) + if block != nil && block.Type != "PUBLIC KEY" { + return false + } + var der []byte + + if block != nil { + der = block.Bytes + } else { + der, err = base64.StdEncoding.DecodeString(str) + if err != nil { + return false + } + } + + key, err := x509.ParsePKIXPublicKey(der) + if err != nil { + return false + } + pubkey, ok := key.(*rsa.PublicKey) + if !ok { + return false + } + bitlen := len(pubkey.N.Bytes()) * 8 + return bitlen == int(keylen) +} + +func toJSONName(tag string) string { + if tag == "" { + return "" + } + + // JSON name always comes first. If there's no options then split[0] is + // JSON name, if JSON name is not set, then split[0] is an empty string. + split := strings.SplitN(tag, ",", 2) + + name := split[0] + + // However it is possible that the field is skipped when + // (de-)serializing from/to JSON, in which case assume that there is no + // tag name to use + if name == "-" { + return "" + } + return name +} + +// ValidateStruct use tags for fields. +// result will be equal to `false` if there are any errors. +func ValidateStruct(s interface{}) (bool, error) { + if s == nil { + return true, nil + } + result := true + var err error + val := reflect.ValueOf(s) + if val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { + val = val.Elem() + } + // we only accept structs + if val.Kind() != reflect.Struct { + return false, fmt.Errorf("function only accepts structs; got %s", val.Kind()) + } + var errs Errors + for i := 0; i < val.NumField(); i++ { + valueField := val.Field(i) + typeField := val.Type().Field(i) + if typeField.PkgPath != "" { + continue // Private field + } + structResult := true + if (valueField.Kind() == reflect.Struct || + (valueField.Kind() == reflect.Ptr && valueField.Elem().Kind() == reflect.Struct)) && + typeField.Tag.Get(tagName) != "-" { + var err error + structResult, err = ValidateStruct(valueField.Interface()) + if err != nil { + errs = append(errs, err) + } + } + resultField, err2 := typeCheck(valueField, typeField, val, nil) + if err2 != nil { + + // Replace structure name with JSON name if there is a tag on the variable + jsonTag := toJSONName(typeField.Tag.Get("json")) + if jsonTag != "" { + switch jsonError := err2.(type) { + case Error: + jsonError.Name = jsonTag + err2 = jsonError + case Errors: + for i2, err3 := range jsonError { + switch customErr := err3.(type) { + case Error: + customErr.Name = jsonTag + jsonError[i2] = customErr + } + } + + err2 = jsonError + } + } + + errs = append(errs, err2) + } + result = result && resultField && structResult + } + if len(errs) > 0 { + err = errs + } + return result, err +} + +// parseTagIntoMap parses a struct tag `valid:required~Some error message,length(2|3)` into map[string]string{"required": "Some error message", "length(2|3)": ""} +func parseTagIntoMap(tag string) tagOptionsMap { + optionsMap := make(tagOptionsMap) + options := strings.Split(tag, ",") + + for _, option := range options { + option = strings.TrimSpace(option) + + validationOptions := strings.Split(option, "~") + if !isValidTag(validationOptions[0]) { + continue + } + if len(validationOptions) == 2 { + optionsMap[validationOptions[0]] = validationOptions[1] + } else { + optionsMap[validationOptions[0]] = "" + } + } + return optionsMap +} + +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 +} + +// IsSSN will validate the given string as a U.S. Social Security Number +func IsSSN(str string) bool { + if str == "" || len(str) != 11 { + return false + } + return rxSSN.MatchString(str) +} + +// IsSemver check if string is valid semantic version +func IsSemver(str string) bool { + return rxSemver.MatchString(str) +} + +// IsTime check if string is valid according to given format +func IsTime(str string, format string) bool { + _, err := time.Parse(format, str) + return err == nil +} + +// IsRFC3339 check if string is valid timestamp value according to RFC3339 +func IsRFC3339(str string) bool { + return IsTime(str, time.RFC3339) +} + +// IsRFC3339WithoutZone check if string is valid timestamp value according to RFC3339 which excludes the timezone. +func IsRFC3339WithoutZone(str string) bool { + return IsTime(str, RF3339WithoutZone) +} + +// IsISO4217 check if string is valid ISO currency code +func IsISO4217(str string) bool { + for _, currency := range ISO4217List { + if str == currency { + return true + } + } + + return false +} + +// ByteLength check string's length +func ByteLength(str string, params ...string) bool { + if len(params) == 2 { + min, _ := ToInt(params[0]) + max, _ := ToInt(params[1]) + return len(str) >= int(min) && len(str) <= int(max) + } + + return false +} + +// RuneLength check string's length +// Alias for StringLength +func RuneLength(str string, params ...string) bool { + return StringLength(str, params...) +} + +// IsRsaPub check whether string is valid RSA key +// Alias for IsRsaPublicKey +func IsRsaPub(str string, params ...string) bool { + if len(params) == 1 { + len, _ := ToInt(params[0]) + return IsRsaPublicKey(str, int(len)) + } + + return false +} + +// StringMatches checks if a string matches a given pattern. +func StringMatches(s string, params ...string) bool { + if len(params) == 1 { + pattern := params[0] + return Matches(s, pattern) + } + return false +} + +// StringLength check string's length (including multi byte strings) +func StringLength(str string, params ...string) bool { + + if len(params) == 2 { + strLength := utf8.RuneCountInString(str) + min, _ := ToInt(params[0]) + max, _ := ToInt(params[1]) + return strLength >= int(min) && strLength <= int(max) + } + + return false +} + +// Range check string's length +func Range(str string, params ...string) bool { + if len(params) == 2 { + value, _ := ToFloat(str) + min, _ := ToFloat(params[0]) + max, _ := ToFloat(params[1]) + return InRange(value, min, max) + } + + return false +} + +func isInRaw(str string, params ...string) bool { + if len(params) == 1 { + rawParams := params[0] + + parsedParams := strings.Split(rawParams, "|") + + return IsIn(str, parsedParams...) + } + + return false +} + +// IsIn check if string str is a member of the set of strings params +func IsIn(str string, params ...string) bool { + for _, param := range params { + if str == param { + return true + } + } + + return false +} + +func checkRequired(v reflect.Value, t reflect.StructField, options tagOptionsMap) (bool, error) { + if requiredOption, isRequired := options["required"]; isRequired { + if len(requiredOption) > 0 { + return false, Error{t.Name, fmt.Errorf(requiredOption), true, "required"} + } + return false, Error{t.Name, fmt.Errorf("non zero value required"), false, "required"} + } else if _, isOptional := options["optional"]; fieldsRequiredByDefault && !isOptional { + return false, Error{t.Name, fmt.Errorf("Missing required field"), false, "required"} + } + // not required and empty is valid + return true, nil +} + +func typeCheck(v reflect.Value, t reflect.StructField, o reflect.Value, options tagOptionsMap) (isValid bool, resultErr error) { + if !v.IsValid() { + return false, nil + } + + tag := t.Tag.Get(tagName) + + // Check if the field should be ignored + switch tag { + case "": + if !fieldsRequiredByDefault { + return true, nil + } + return false, Error{t.Name, fmt.Errorf("All fields are required to at least have one validation defined"), false, "required"} + case "-": + return true, nil + } + + isRootType := false + if options == nil { + isRootType = true + options = parseTagIntoMap(tag) + } + + if isEmptyValue(v) { + // an empty value is not validated, check only required + return checkRequired(v, t, options) + } + + var customTypeErrors Errors + for validatorName, customErrorMessage := range options { + if validatefunc, ok := CustomTypeTagMap.Get(validatorName); ok { + delete(options, validatorName) + + if result := validatefunc(v.Interface(), o.Interface()); !result { + if len(customErrorMessage) > 0 { + customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf(customErrorMessage), CustomErrorMessageExists: true, Validator: stripParams(validatorName)}) + continue + } + customTypeErrors = append(customTypeErrors, Error{Name: t.Name, Err: fmt.Errorf("%s does not validate as %s", fmt.Sprint(v), validatorName), CustomErrorMessageExists: false, Validator: stripParams(validatorName)}) + } + } + } + + if len(customTypeErrors.Errors()) > 0 { + return false, customTypeErrors + } + + if isRootType { + // Ensure that we've checked the value by all specified validators before report that the value is valid + defer func() { + delete(options, "optional") + delete(options, "required") + + if isValid && resultErr == nil && len(options) != 0 { + for validator := range options { + isValid = false + resultErr = Error{t.Name, fmt.Errorf( + "The following validator is invalid or can't be applied to the field: %q", validator), false, stripParams(validator)} + return + } + } + }() + } + + switch v.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, + reflect.String: + // for each tag option check the map of validator functions + for validatorSpec, customErrorMessage := range options { + var negate bool + validator := validatorSpec + customMsgExists := len(customErrorMessage) > 0 + + // Check whether the tag looks like '!something' or 'something' + if validator[0] == '!' { + validator = validator[1:] + negate = true + } + + // Check for param validators + for key, value := range ParamTagRegexMap { + ps := value.FindStringSubmatch(validator) + if len(ps) == 0 { + continue + } + + validatefunc, ok := ParamTagMap[key] + if !ok { + continue + } + + delete(options, validatorSpec) + + switch v.Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + + field := fmt.Sprint(v) // make value into string, then validate with regex + if result := validatefunc(field, ps[1:]...); (!result && !negate) || (result && negate) { + if customMsgExists { + return false, Error{t.Name, fmt.Errorf(customErrorMessage), customMsgExists, stripParams(validatorSpec)} + } + if negate { + return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec)} + } + return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec)} + } + default: + // type not yet supported, fail + return false, Error{t.Name, fmt.Errorf("Validator %s doesn't support kind %s", validator, v.Kind()), false, stripParams(validatorSpec)} + } + } + + if validatefunc, ok := TagMap[validator]; ok { + delete(options, validatorSpec) + + switch v.Kind() { + case reflect.String: + field := fmt.Sprint(v) // make value into string, then validate with regex + if result := validatefunc(field); !result && !negate || result && negate { + if customMsgExists { + return false, Error{t.Name, fmt.Errorf(customErrorMessage), customMsgExists, stripParams(validatorSpec)} + } + if negate { + return false, Error{t.Name, fmt.Errorf("%s does validate as %s", field, validator), customMsgExists, stripParams(validatorSpec)} + } + return false, Error{t.Name, fmt.Errorf("%s does not validate as %s", field, validator), customMsgExists, stripParams(validatorSpec)} + } + default: + //Not Yet Supported Types (Fail here!) + err := fmt.Errorf("Validator %s doesn't support kind %s for value %v", validator, v.Kind(), v) + return false, Error{t.Name, err, false, stripParams(validatorSpec)} + } + } + } + return true, nil + case reflect.Map: + if v.Type().Key().Kind() != reflect.String { + return false, &UnsupportedTypeError{v.Type()} + } + var sv stringValues + sv = v.MapKeys() + sort.Sort(sv) + result := true + for _, k := range sv { + var resultItem bool + var err error + if v.MapIndex(k).Kind() != reflect.Struct { + resultItem, err = typeCheck(v.MapIndex(k), t, o, options) + if err != nil { + return false, err + } + } else { + resultItem, err = ValidateStruct(v.MapIndex(k).Interface()) + if err != nil { + return false, err + } + } + result = result && resultItem + } + return result, nil + case reflect.Slice, reflect.Array: + result := true + for i := 0; i < v.Len(); i++ { + var resultItem bool + var err error + if v.Index(i).Kind() != reflect.Struct { + resultItem, err = typeCheck(v.Index(i), t, o, options) + if err != nil { + return false, err + } + } else { + resultItem, err = ValidateStruct(v.Index(i).Interface()) + if err != nil { + return false, err + } + } + result = result && resultItem + } + return result, nil + case reflect.Interface: + // If the value is an interface then encode its element + if v.IsNil() { + return true, nil + } + return ValidateStruct(v.Interface()) + case reflect.Ptr: + // If the value is a pointer then check its element + if v.IsNil() { + return true, nil + } + return typeCheck(v.Elem(), t, o, options) + case reflect.Struct: + return ValidateStruct(v.Interface()) + default: + return false, &UnsupportedTypeError{v.Type()} + } +} + +func stripParams(validatorString string) string { + return paramsRegexp.ReplaceAllString(validatorString, "") +} + +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.String, reflect.Array: + return v.Len() == 0 + case reflect.Map, reflect.Slice: + return v.Len() == 0 || v.IsNil() + 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: + return v.IsNil() + } + + return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) +} + +// ErrorByField returns error for specified field of the struct +// validated by ValidateStruct or empty string if there are no errors +// or this field doesn't exists or doesn't have any errors. +func ErrorByField(e error, field string) string { + if e == nil { + return "" + } + return ErrorsByField(e)[field] +} + +// ErrorsByField returns map of errors of the struct validated +// by ValidateStruct or empty map if there are no errors. +func ErrorsByField(e error) map[string]string { + m := make(map[string]string) + if e == nil { + return m + } + // prototype for ValidateStruct + + switch e.(type) { + case Error: + m[e.(Error).Name] = e.(Error).Err.Error() + case Errors: + for _, item := range e.(Errors).Errors() { + n := ErrorsByField(item) + for k, v := range n { + m[k] = v + } + } + } + + return m +} + +// Error returns string equivalent for reflect.Type +func (e *UnsupportedTypeError) Error() string { + return "validator: unsupported type: " + e.Type.String() +} + +func (sv stringValues) Len() int { return len(sv) } +func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } +func (sv stringValues) get(i int) string { return sv[i].String() } diff --git a/vendor/github.com/asaskevich/govalidator/wercker.yml b/vendor/github.com/asaskevich/govalidator/wercker.yml new file mode 100644 index 000000000..cac7a5fcf --- /dev/null +++ b/vendor/github.com/asaskevich/govalidator/wercker.yml @@ -0,0 +1,15 @@ +box: golang +build: + steps: + - setup-go-workspace + + - script: + name: go get + code: | + go version + go get -t ./... + + - script: + name: go test + code: | + go test -race ./... 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 000000000..744875676 --- /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 000000000..4562f9992 --- /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 000000000..2ae5456d5 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml @@ -0,0 +1,48 @@ +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: 19 + 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 000000000..927d75d1b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/buf.go @@ -0,0 +1,258 @@ +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:] + } +} + +func (w *tdsBuffer) WriteByte(b byte) error { + if int(w.wpos) == len(w.wbuf) || w.wpos == w.packetSize { + 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) > r.packetSize { + 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 000000000..76800d54a --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go @@ -0,0 +1,554 @@ +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: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDateTime2(val, int(col.ti.Scale)) + res.ti.Size = len(res.buffer) + default: + err = fmt.Errorf("mssql: invalid type for datetime2 column: %s", val) + return + } + case typeDateTimeOffsetN: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + + default: + err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %s", val) + return + } + case typeDateN: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDate(val) + res.ti.Size = len(res.buffer) + 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.buffer = encodeDateTim4(val) + res.ti.Size = len(res.buffer) + } else if col.ti.Size == 8 { + res.buffer = encodeDateTime(val) + res.ti.Size = len(res.buffer) + } 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 000000000..4824df9ad --- /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 000000000..372f64b4e --- /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 000000000..2e54929c5 --- /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 000000000..2e5baceec --- /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 000000000..8dc2279ea --- /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 000000000..ae7b03bf1 --- /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 000000000..5c8094ec3 --- /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 000000000..dc5896770 --- /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 000000000..5ae870354 --- /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 000000000..52c8e07aa --- /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 000000000..5d8864a52 --- /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 000000000..60619895d --- /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 000000000..ffd04b3e5 --- /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 000000000..492da72ea --- /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 000000000..80be52c59 --- /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 000000000..76dedfb8e --- /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 000000000..927ab249e --- /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 000000000..723bf6c39 --- /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 000000000..5fc137742 --- /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 000000000..d1fac12e2 --- /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 000000000..52c708dfa --- /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 000000000..1301cd0f0 --- /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 000000000..9b8c551e8 --- /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 000000000..552f13932 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql.go @@ -0,0 +1,877 @@ +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) + if err != nil { + return + } + } 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.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + } else { + res.ti.TypeId = typeDateTimeN + res.buffer = encodeDateTime(val) + res.ti.Size = len(res.buffer) + } + 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 +} + +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_go110.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go new file mode 100644 index 000000000..3d5ab57a5 --- /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_go19.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go new file mode 100644 index 000000000..07b1ad7cd --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go @@ -0,0 +1,175 @@ +// +build go1.9 + +package mssql + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "reflect" + "time" + + // "github.com/cockroachdb/apd" + "cloud.google.com/go/civil" +) + +// Type alias provided for compatibility. + +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 + + if v.Dest == nil { + return errors.New("destination is a nil pointer") + } + + dest_info := reflect.ValueOf(v.Dest) + if dest_info.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + + if dest_info.IsNil() { + return errors.New("destination is a nil pointer") + } + + pointed_value := reflect.Indirect(dest_info) + + // don't allow pointer to a pointer, only pointer to a value can be handled + // correctly + if pointed_value.Kind() == reflect.Ptr { + return errors.New("destination is a pointer to a pointer") + } + + // Unwrap the Out value and check the inner value. + lnv := *nv + lnv.Value = pointed_value.Interface() + err := c.CheckNamedValue(&lnv) + 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: + conv_val, err := driver.DefaultParameterConverter.ConvertValue(v) + nv.Value = conv_val + return err + } +} + +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.buffer = encodeDateTime(t) + res.ti.Size = len(res.buffer) + case DateTimeOffset: + res.ti.TypeId = typeDateTimeOffsetN + res.ti.Scale = 7 + res.buffer = encodeDateTimeOffset(time.Time(val), int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case civil.Date: + res.ti.TypeId = typeDateN + res.buffer = encodeDate(val.In(time.UTC)) + res.ti.Size = len(res.buffer) + case civil.DateTime: + res.ti.TypeId = typeDateTime2N + res.ti.Scale = 7 + res.buffer = encodeDateTime2(val.In(time.UTC), int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case civil.Time: + res.ti.TypeId = typeTimeN + res.ti.Scale = 7 + res.buffer = encodeTime(val.Hour, val.Minute, val.Second, val.Nanosecond, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + 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 000000000..9680f5107 --- /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 000000000..e3864d1a2 --- /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 000000000..7c0cc4f78 --- /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 000000000..8021ca603 --- /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 000000000..4ca22578f --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/rpc.go @@ -0,0 +1,89 @@ +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 +} + +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 000000000..9b5bc6893 --- /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 000000000..a45711d55 --- /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 000000000..67fdcc2e1 --- /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 000000000..c075b23be --- /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 000000000..cb6436816 --- /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 000000000..e37a423fd --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/types.go @@ -0,0 +1,1561 @@ +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 encodeDateTim4(val time.Time) (buf []byte) { + buf = make([]byte, 4) + + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + dur := val.Sub(ref) + days := dur / (24 * time.Hour) + mins := val.Hour()*60 + val.Minute() + if days < 0 { + days = 0 + mins = 0 + } + + binary.LittleEndian.PutUint16(buf[:2], uint16(days)) + binary.LittleEndian.PutUint16(buf[2:], uint16(mins)) + return +} + +// encodes datetime value +// type identifier is typeDateTimeN +func encodeDateTime(t time.Time) (res []byte) { + // base date in days since Jan 1st 1900 + basedays := gregorianDays(1900, 1) + // days since Jan 1st 1900 (same TZ as t) + days := gregorianDays(t.Year(), t.YearDay()) - basedays + tm := 300*(t.Second()+t.Minute()*60+t.Hour()*60*60) + t.Nanosecond()*300/1e9 + // minimum and maximum possible + mindays := gregorianDays(1753, 1) - basedays + maxdays := gregorianDays(9999, 365) - basedays + if days < mindays { + days = mindays + tm = 0 + } + if days > maxdays { + days = maxdays + tm = (23*60*60+59*60+59)*300 + 299 + } + res = make([]byte, 8) + binary.LittleEndian.PutUint32(res[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res[4:8], uint32(tm)) + return +} + +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 encodeDate(val time.Time) (buf []byte) { + days, _, _ := dateTime2(val) + buf = make([]byte, 3) + buf[0] = byte(days) + buf[1] = byte(days >> 8) + buf[2] = byte(days >> 16) + return +} + +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 +} + +// calculate size of time field in bytes +func calcTimeSize(scale int) int { + if scale <= 2 { + return 3 + } else if scale <= 4 { + return 4 + } else { + return 5 + } +} + +// writes time value into a field buffer +// buffer should be at least calcTimeSize long +func encodeTimeInt(seconds, ns, scale int, buf []byte) { + ns_total := int64(seconds)*1000*1000*1000 + int64(ns) + t := ns_total / int64(math.Pow10(int(scale)*-1)*1e9) + buf[0] = byte(t) + buf[1] = byte(t >> 8) + buf[2] = byte(t >> 16) + buf[3] = byte(t >> 24) + buf[4] = byte(t >> 32) +} + +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 encodeTime(hour, minute, second, ns, scale int) (buf []byte) { + seconds := hour*3600 + minute*60 + second + buf = make([]byte, calcTimeSize(scale)) + encodeTimeInt(seconds, ns, scale, buf) + return +} + +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 encodeDateTime2(val time.Time, scale int) (buf []byte) { + days, seconds, ns := dateTime2(val) + timesize := calcTimeSize(scale) + buf = make([]byte, 3+timesize) + encodeTimeInt(seconds, ns, scale, buf) + buf[timesize] = byte(days) + buf[timesize+1] = byte(days >> 8) + buf[timesize+2] = byte(days >> 16) + return +} + +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 encodeDateTimeOffset(val time.Time, scale int) (buf []byte) { + timesize := calcTimeSize(scale) + buf = make([]byte, timesize+2+3) + days, seconds, ns := dateTime2(val.In(time.UTC)) + encodeTimeInt(seconds, ns, scale, buf) + buf[timesize] = byte(days) + buf[timesize+1] = byte(days >> 8) + buf[timesize+2] = byte(days >> 16) + _, offset := val.Zone() + offset /= 60 + buf[timesize+3] = byte(offset) + buf[timesize+4] = byte(offset >> 8) + return +} + +// returns days since Jan 1st 0001 in Gregorian calendar +func gregorianDays(year, yearday int) int { + year0 := year - 1 + return year0*365 + year0/4 - year0/100 + year0/400 + yearday - 1 +} + +func dateTime2(t time.Time) (days int, seconds int, ns int) { + // days since Jan 1 1 (in same TZ as t) + days = gregorianDays(t.Year(), t.YearDay()) + seconds = t.Second() + t.Minute()*60 + t.Hour()*60*60 + ns = t.Nanosecond() + if days < 0 { + days = 0 + seconds = 0 + ns = 0 + } + max := gregorianDays(9999, 365) + if days > max { + days = max + seconds = 59 + 59*60 + 23*60*60 + ns = 999999900 + } + 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 000000000..c8ef3149b --- /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/fatih/structs/LICENSE b/vendor/github.com/fatih/structs/LICENSE new file mode 100644 index 000000000..34504e4b3 --- /dev/null +++ b/vendor/github.com/fatih/structs/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 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. \ No newline at end of file diff --git a/vendor/github.com/fatih/structs/README.md b/vendor/github.com/fatih/structs/README.md new file mode 100644 index 000000000..44e01006e --- /dev/null +++ b/vendor/github.com/fatih/structs/README.md @@ -0,0 +1,163 @@ +# Structs [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/structs) [![Build Status](http://img.shields.io/travis/fatih/structs.svg?style=flat-square)](https://travis-ci.org/fatih/structs) [![Coverage Status](http://img.shields.io/coveralls/fatih/structs.svg?style=flat-square)](https://coveralls.io/r/fatih/structs) + +Structs contains various utilities to work with Go (Golang) structs. It was +initially used by me to convert a struct into a `map[string]interface{}`. With +time I've added other utilities for structs. It's basically a high level +package based on primitives from the reflect package. Feel free to add new +functions or improve the existing code. + +## Install + +```bash +go get github.com/fatih/structs +``` + +## Usage and Examples + +Just like the standard lib `strings`, `bytes` and co packages, `structs` has +many global functions to manipulate or organize your struct data. Lets define +and declare a struct: + +```go +type Server struct { + Name string `json:"name,omitempty"` + ID int + Enabled bool + users []string // not exported + http.Server // embedded +} + +server := &Server{ + Name: "gopher", + ID: 123456, + Enabled: true, +} +``` + +```go +// Convert a struct to a map[string]interface{} +// => {"Name":"gopher", "ID":123456, "Enabled":true} +m := structs.Map(server) + +// Convert the values of a struct to a []interface{} +// => ["gopher", 123456, true] +v := structs.Values(server) + +// Convert the names of a struct to a []string +// (see "Names methods" for more info about fields) +n := structs.Names(server) + +// Convert the values of a struct to a []*Field +// (see "Field methods" for more info about fields) +f := structs.Fields(server) + +// Return the struct name => "Server" +n := structs.Name(server) + +// Check if any field of a struct is initialized or not. +h := structs.HasZero(server) + +// Check if all fields of a struct is initialized or not. +z := structs.IsZero(server) + +// Check if server is a struct or a pointer to struct +i := structs.IsStruct(server) +``` + +### Struct methods + +The structs functions can be also used as independent methods by creating a new +`*structs.Struct`. This is handy if you want to have more control over the +structs (such as retrieving a single Field). + +```go +// Create a new struct type: +s := structs.New(server) + +m := s.Map() // Get a map[string]interface{} +v := s.Values() // Get a []interface{} +f := s.Fields() // Get a []*Field +n := s.Names() // Get a []string +f := s.Field(name) // Get a *Field based on the given field name +f, ok := s.FieldOk(name) // Get a *Field based on the given field name +n := s.Name() // Get the struct name +h := s.HasZero() // Check if any field is initialized +z := s.IsZero() // Check if all fields are initialized +``` + +### Field methods + +We can easily examine a single Field for more detail. Below you can see how we +get and interact with various field methods: + + +```go +s := structs.New(server) + +// Get the Field struct for the "Name" field +name := s.Field("Name") + +// Get the underlying value, value => "gopher" +value := name.Value().(string) + +// Set the field's value +name.Set("another gopher") + +// Get the field's kind, kind => "string" +name.Kind() + +// Check if the field is exported or not +if name.IsExported() { + fmt.Println("Name field is exported") +} + +// Check if the value is a zero value, such as "" for string, 0 for int +if !name.IsZero() { + fmt.Println("Name is initialized") +} + +// Check if the field is an anonymous (embedded) field +if !name.IsEmbedded() { + fmt.Println("Name is not an embedded field") +} + +// Get the Field's tag value for tag name "json", tag value => "name,omitempty" +tagValue := name.Tag("json") +``` + +Nested structs are supported too: + +```go +addrField := s.Field("Server").Field("Addr") + +// Get the value for addr +a := addrField.Value().(string) + +// Or get all fields +httpServer := s.Field("Server").Fields() +``` + +We can also get a slice of Fields from the Struct type to iterate over all +fields. This is handy if you wish to examine all fields: + +```go +s := structs.New(server) + +for _, f := range s.Fields() { + fmt.Printf("field name: %+v\n", f.Name()) + + if f.IsExported() { + fmt.Printf("value : %+v\n", f.Value()) + fmt.Printf("is zero : %+v\n", f.IsZero()) + } +} +``` + +## Credits + + * [Fatih Arslan](https://github.com/fatih) + * [Cihangir Savas](https://github.com/cihangir) + +## License + +The MIT License (MIT) - see LICENSE.md for more details diff --git a/vendor/github.com/fatih/structs/field.go b/vendor/github.com/fatih/structs/field.go new file mode 100644 index 000000000..e69783230 --- /dev/null +++ b/vendor/github.com/fatih/structs/field.go @@ -0,0 +1,141 @@ +package structs + +import ( + "errors" + "fmt" + "reflect" +) + +var ( + errNotExported = errors.New("field is not exported") + errNotSettable = errors.New("field is not settable") +) + +// Field represents a single struct field that encapsulates high level +// functions around the field. +type Field struct { + value reflect.Value + field reflect.StructField + defaultTag string +} + +// Tag returns the value associated with key in the tag string. If there is no +// such key in the tag, Tag returns the empty string. +func (f *Field) Tag(key string) string { + return f.field.Tag.Get(key) +} + +// Value returns the underlying value of the field. It panics if the field +// is not exported. +func (f *Field) Value() interface{} { + return f.value.Interface() +} + +// IsEmbedded returns true if the given field is an anonymous field (embedded) +func (f *Field) IsEmbedded() bool { + return f.field.Anonymous +} + +// IsExported returns true if the given field is exported. +func (f *Field) IsExported() bool { + return f.field.PkgPath == "" +} + +// IsZero returns true if the given field is not initialized (has a zero value). +// It panics if the field is not exported. +func (f *Field) IsZero() bool { + zero := reflect.Zero(f.value.Type()).Interface() + current := f.Value() + + return reflect.DeepEqual(current, zero) +} + +// Name returns the name of the given field +func (f *Field) Name() string { + return f.field.Name +} + +// Kind returns the fields kind, such as "string", "map", "bool", etc .. +func (f *Field) Kind() reflect.Kind { + return f.value.Kind() +} + +// Set sets the field to given value v. It returns an error if the field is not +// settable (not addressable or not exported) or if the given value's type +// doesn't match the fields type. +func (f *Field) Set(val interface{}) error { + // we can't set unexported fields, so be sure this field is exported + if !f.IsExported() { + return errNotExported + } + + // do we get here? not sure... + if !f.value.CanSet() { + return errNotSettable + } + + given := reflect.ValueOf(val) + + if f.value.Kind() != given.Kind() { + return fmt.Errorf("wrong kind. got: %s want: %s", given.Kind(), f.value.Kind()) + } + + f.value.Set(given) + return nil +} + +// Zero sets the field to its zero value. It returns an error if the field is not +// settable (not addressable or not exported). +func (f *Field) Zero() error { + zero := reflect.Zero(f.value.Type()).Interface() + return f.Set(zero) +} + +// Fields returns a slice of Fields. This is particular handy to get the fields +// of a nested struct . A struct tag with the content of "-" ignores the +// checking of that particular field. Example: +// +// // Field is ignored by this package. +// Field *http.Request `structs:"-"` +// +// It panics if field is not exported or if field's kind is not struct +func (f *Field) Fields() []*Field { + return getFields(f.value, f.defaultTag) +} + +// Field returns the field from a nested struct. It panics if the nested struct +// is not exported or if the field was not found. +func (f *Field) Field(name string) *Field { + field, ok := f.FieldOk(name) + if !ok { + panic("field not found") + } + + return field +} + +// FieldOk returns the field from a nested struct. The boolean returns whether +// the field was found (true) or not (false). +func (f *Field) FieldOk(name string) (*Field, bool) { + value := &f.value + // value must be settable so we need to make sure it holds the address of the + // variable and not a copy, so we can pass the pointer to strctVal instead of a + // copy (which is not assigned to any variable, hence not settable). + // see "https://blog.golang.org/laws-of-reflection#TOC_8." + if f.value.Kind() != reflect.Ptr { + a := f.value.Addr() + value = &a + } + v := strctVal(value.Interface()) + t := v.Type() + + field, ok := t.FieldByName(name) + if !ok { + return nil, false + } + + return &Field{ + field: field, + value: v.FieldByName(name), + }, true +} diff --git a/vendor/github.com/fatih/structs/structs.go b/vendor/github.com/fatih/structs/structs.go new file mode 100644 index 000000000..3a8770652 --- /dev/null +++ b/vendor/github.com/fatih/structs/structs.go @@ -0,0 +1,584 @@ +// Package structs contains various utilities functions to work with structs. +package structs + +import ( + "fmt" + + "reflect" +) + +var ( + // DefaultTagName is the default tag name for struct fields which provides + // a more granular to tweak certain structs. Lookup the necessary functions + // for more info. + DefaultTagName = "structs" // struct's field default tag name +) + +// Struct encapsulates a struct type to provide several high level functions +// around the struct. +type Struct struct { + raw interface{} + value reflect.Value + TagName string +} + +// New returns a new *Struct with the struct s. It panics if the s's kind is +// not struct. +func New(s interface{}) *Struct { + return &Struct{ + raw: s, + value: strctVal(s), + TagName: DefaultTagName, + } +} + +// Map converts the given struct to a map[string]interface{}, where the keys +// of the map are the field names and the values of the map the associated +// values of the fields. The default key string is the struct field name but +// can be changed in the struct field's tag value. The "structs" key in the +// struct's field tag value is the key name. Example: +// +// // Field appears in map as key "myName". +// Name string `structs:"myName"` +// +// A tag value with the content of "-" ignores that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// A tag value with the content of "string" uses the stringer to get the value. Example: +// +// // The value will be output of Animal's String() func. +// // Map will panic if Animal does not implement String(). +// Field *Animal `structs:"field,string"` +// +// A tag value with the option of "flatten" used in a struct field is to flatten its fields +// in the output map. Example: +// +// // The FieldStruct's fields will be flattened into the output map. +// FieldStruct time.Time `structs:",flatten"` +// +// A tag value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Field is not processed further by this package. +// Field time.Time `structs:"myName,omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// A tag value with the option of "omitempty" ignores that particular field if +// the field value is empty. Example: +// +// // Field appears in map as key "myName", but the field is +// // skipped if empty. +// Field string `structs:"myName,omitempty"` +// +// // Field appears in map as key "Field" (the default), but +// // the field is skipped if empty. +// Field string `structs:",omitempty"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. +func (s *Struct) Map() map[string]interface{} { + out := make(map[string]interface{}) + s.FillMap(out) + return out +} + +// FillMap is the same as Map. Instead of returning the output, it fills the +// given map. +func (s *Struct) FillMap(out map[string]interface{}) { + if out == nil { + return + } + + fields := s.structFields() + + for _, field := range fields { + name := field.Name + val := s.value.FieldByName(name) + isSubStruct := false + var finalVal interface{} + + tagName, tagOpts := parseTag(field.Tag.Get(s.TagName)) + if tagName != "" { + name = tagName + } + + // if the value is a zero value and the field is marked as omitempty do + // not include + if tagOpts.Has("omitempty") { + zero := reflect.Zero(val.Type()).Interface() + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + continue + } + } + + if !tagOpts.Has("omitnested") { + finalVal = s.nested(val) + + v := reflect.ValueOf(val.Interface()) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + switch v.Kind() { + case reflect.Map, reflect.Struct: + isSubStruct = true + } + } else { + finalVal = val.Interface() + } + + if tagOpts.Has("string") { + s, ok := val.Interface().(fmt.Stringer) + if ok { + out[name] = s.String() + } + continue + } + + if isSubStruct && (tagOpts.Has("flatten")) { + for k := range finalVal.(map[string]interface{}) { + out[k] = finalVal.(map[string]interface{})[k] + } + } else { + out[name] = finalVal + } + } +} + +// Values converts the given s struct's field values to a []interface{}. A +// struct tag with the content of "-" ignores the that particular field. +// Example: +// +// // Field is ignored by this package. +// Field int `structs:"-"` +// +// A value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Fields is not processed further by this package. +// Field time.Time `structs:",omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// A tag value with the option of "omitempty" ignores that particular field and +// is not added to the values if the field value is empty. Example: +// +// // Field is skipped if empty +// Field string `structs:",omitempty"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. +func (s *Struct) Values() []interface{} { + fields := s.structFields() + + var t []interface{} + + for _, field := range fields { + val := s.value.FieldByName(field.Name) + + _, tagOpts := parseTag(field.Tag.Get(s.TagName)) + + // if the value is a zero value and the field is marked as omitempty do + // not include + if tagOpts.Has("omitempty") { + zero := reflect.Zero(val.Type()).Interface() + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + continue + } + } + + if tagOpts.Has("string") { + s, ok := val.Interface().(fmt.Stringer) + if ok { + t = append(t, s.String()) + } + continue + } + + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { + // look out for embedded structs, and convert them to a + // []interface{} to be added to the final values slice + t = append(t, Values(val.Interface())...) + } else { + t = append(t, val.Interface()) + } + } + + return t +} + +// Fields returns a slice of Fields. A struct tag with the content of "-" +// ignores the checking of that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// It panics if s's kind is not struct. +func (s *Struct) Fields() []*Field { + return getFields(s.value, s.TagName) +} + +// Names returns a slice of field names. A struct tag with the content of "-" +// ignores the checking of that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// It panics if s's kind is not struct. +func (s *Struct) Names() []string { + fields := getFields(s.value, s.TagName) + + names := make([]string, len(fields)) + + for i, field := range fields { + names[i] = field.Name() + } + + return names +} + +func getFields(v reflect.Value, tagName string) []*Field { + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + t := v.Type() + + var fields []*Field + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + + if tag := field.Tag.Get(tagName); tag == "-" { + continue + } + + f := &Field{ + field: field, + value: v.FieldByName(field.Name), + } + + fields = append(fields, f) + + } + + return fields +} + +// Field returns a new Field struct that provides several high level functions +// around a single struct field entity. It panics if the field is not found. +func (s *Struct) Field(name string) *Field { + f, ok := s.FieldOk(name) + if !ok { + panic("field not found") + } + + return f +} + +// FieldOk returns a new Field struct that provides several high level functions +// around a single struct field entity. The boolean returns true if the field +// was found. +func (s *Struct) FieldOk(name string) (*Field, bool) { + t := s.value.Type() + + field, ok := t.FieldByName(name) + if !ok { + return nil, false + } + + return &Field{ + field: field, + value: s.value.FieldByName(name), + defaultTag: s.TagName, + }, true +} + +// IsZero returns true if all fields in a struct is a zero value (not +// initialized) A struct tag with the content of "-" ignores the checking of +// that particular field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// A value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Field is not processed further by this package. +// Field time.Time `structs:"myName,omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. It panics if s's kind is not struct. +func (s *Struct) IsZero() bool { + fields := s.structFields() + + for _, field := range fields { + val := s.value.FieldByName(field.Name) + + _, tagOpts := parseTag(field.Tag.Get(s.TagName)) + + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { + ok := IsZero(val.Interface()) + if !ok { + return false + } + + continue + } + + // zero value of the given field, such as "" for string, 0 for int + zero := reflect.Zero(val.Type()).Interface() + + // current value of the given field + current := val.Interface() + + if !reflect.DeepEqual(current, zero) { + return false + } + } + + return true +} + +// HasZero returns true if a field in a struct is not initialized (zero value). +// A struct tag with the content of "-" ignores the checking of that particular +// field. Example: +// +// // Field is ignored by this package. +// Field bool `structs:"-"` +// +// A value with the option of "omitnested" stops iterating further if the type +// is a struct. Example: +// +// // Field is not processed further by this package. +// Field time.Time `structs:"myName,omitnested"` +// Field *http.Request `structs:",omitnested"` +// +// Note that only exported fields of a struct can be accessed, non exported +// fields will be neglected. It panics if s's kind is not struct. +func (s *Struct) HasZero() bool { + fields := s.structFields() + + for _, field := range fields { + val := s.value.FieldByName(field.Name) + + _, tagOpts := parseTag(field.Tag.Get(s.TagName)) + + if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") { + ok := HasZero(val.Interface()) + if ok { + return true + } + + continue + } + + // zero value of the given field, such as "" for string, 0 for int + zero := reflect.Zero(val.Type()).Interface() + + // current value of the given field + current := val.Interface() + + if reflect.DeepEqual(current, zero) { + return true + } + } + + return false +} + +// Name returns the structs's type name within its package. For more info refer +// to Name() function. +func (s *Struct) Name() string { + return s.value.Type().Name() +} + +// structFields returns the exported struct fields for a given s struct. This +// is a convenient helper method to avoid duplicate code in some of the +// functions. +func (s *Struct) structFields() []reflect.StructField { + t := s.value.Type() + + var f []reflect.StructField + + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + // we can't access the value of unexported fields + if field.PkgPath != "" { + continue + } + + // don't check if it's omitted + if tag := field.Tag.Get(s.TagName); tag == "-" { + continue + } + + f = append(f, field) + } + + return f +} + +func strctVal(s interface{}) reflect.Value { + v := reflect.ValueOf(s) + + // if pointer get the underlying element≤ + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + panic("not struct") + } + + return v +} + +// Map converts the given struct to a map[string]interface{}. For more info +// refer to Struct types Map() method. It panics if s's kind is not struct. +func Map(s interface{}) map[string]interface{} { + return New(s).Map() +} + +// FillMap is the same as Map. Instead of returning the output, it fills the +// given map. +func FillMap(s interface{}, out map[string]interface{}) { + New(s).FillMap(out) +} + +// Values converts the given struct to a []interface{}. For more info refer to +// Struct types Values() method. It panics if s's kind is not struct. +func Values(s interface{}) []interface{} { + return New(s).Values() +} + +// Fields returns a slice of *Field. For more info refer to Struct types +// Fields() method. It panics if s's kind is not struct. +func Fields(s interface{}) []*Field { + return New(s).Fields() +} + +// Names returns a slice of field names. For more info refer to Struct types +// Names() method. It panics if s's kind is not struct. +func Names(s interface{}) []string { + return New(s).Names() +} + +// IsZero returns true if all fields is equal to a zero value. For more info +// refer to Struct types IsZero() method. It panics if s's kind is not struct. +func IsZero(s interface{}) bool { + return New(s).IsZero() +} + +// HasZero returns true if any field is equal to a zero value. For more info +// refer to Struct types HasZero() method. It panics if s's kind is not struct. +func HasZero(s interface{}) bool { + return New(s).HasZero() +} + +// IsStruct returns true if the given variable is a struct or a pointer to +// struct. +func IsStruct(s interface{}) bool { + v := reflect.ValueOf(s) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + // uninitialized zero value of a struct + if v.Kind() == reflect.Invalid { + return false + } + + return v.Kind() == reflect.Struct +} + +// Name returns the structs's type name within its package. It returns an +// empty string for unnamed types. It panics if s's kind is not struct. +func Name(s interface{}) string { + return New(s).Name() +} + +// nested retrieves recursively all types for the given value and returns the +// nested value. +func (s *Struct) nested(val reflect.Value) interface{} { + var finalVal interface{} + + v := reflect.ValueOf(val.Interface()) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + switch v.Kind() { + case reflect.Struct: + n := New(val.Interface()) + n.TagName = s.TagName + m := n.Map() + + // do not add the converted value if there are no exported fields, ie: + // time.Time + if len(m) == 0 { + finalVal = val.Interface() + } else { + finalVal = m + } + case reflect.Map: + // get the element type of the map + mapElem := val.Type() + switch val.Type().Kind() { + case reflect.Ptr, reflect.Array, reflect.Map, + reflect.Slice, reflect.Chan: + mapElem = val.Type().Elem() + if mapElem.Kind() == reflect.Ptr { + mapElem = mapElem.Elem() + } + } + + // only iterate over struct types, ie: map[string]StructType, + // map[string][]StructType, + if mapElem.Kind() == reflect.Struct || + (mapElem.Kind() == reflect.Slice && + mapElem.Elem().Kind() == reflect.Struct) { + m := make(map[string]interface{}, val.Len()) + for _, k := range val.MapKeys() { + m[k.String()] = s.nested(val.MapIndex(k)) + } + finalVal = m + break + } + + // TODO(arslan): should this be optional? + finalVal = val.Interface() + case reflect.Slice, reflect.Array: + if val.Type().Kind() == reflect.Interface { + finalVal = val.Interface() + break + } + + // TODO(arslan): should this be optional? + // do not iterate of non struct types, just pass the value. Ie: []int, + // []string, co... We only iterate further if it's a struct. + // i.e []foo or []*foo + if val.Type().Elem().Kind() != reflect.Struct && + !(val.Type().Elem().Kind() == reflect.Ptr && + val.Type().Elem().Elem().Kind() == reflect.Struct) { + finalVal = val.Interface() + break + } + + slices := make([]interface{}, val.Len()) + for x := 0; x < val.Len(); x++ { + slices[x] = s.nested(val.Index(x)) + } + finalVal = slices + default: + finalVal = val.Interface() + } + + return finalVal +} diff --git a/vendor/github.com/fatih/structs/tags.go b/vendor/github.com/fatih/structs/tags.go new file mode 100644 index 000000000..136a31eba --- /dev/null +++ b/vendor/github.com/fatih/structs/tags.go @@ -0,0 +1,32 @@ +package structs + +import "strings" + +// tagOptions contains a slice of tag options +type tagOptions []string + +// Has returns true if the given option is available in tagOptions +func (t tagOptions) Has(opt string) bool { + for _, tagOpt := range t { + if tagOpt == opt { + return true + } + } + + return false +} + +// parseTag splits a struct field's tag into its name and a list of options +// which comes after a name. A tag is in the form of: "name,option1,option2". +// The name can be neglectected. +func parseTag(tag string) (string, tagOptions) { + // tag is one of followings: + // "" + // "name" + // "name,opt" + // "name,opt,opt2" + // ",opt" + + res := strings.Split(tag, ",") + return res[0], res[1:] +} 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 000000000..73ff68fbc --- /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 000000000..2d87d74c9 --- /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 000000000..8fe16bcb4 --- /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 000000000..14e2f777f --- /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 000000000..2e9b07eeb --- /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/auth.go b/vendor/github.com/go-sql-driver/mysql/auth.go new file mode 100644 index 000000000..0b59f52ee --- /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 000000000..eb4748bf4 --- /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 000000000..136c9e4d1 --- /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 000000000..911be2060 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection.go @@ -0,0 +1,654 @@ +// 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 ( + "context" + "database/sql" + "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: + } +} + +// 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 000000000..b1e6b85ef --- /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 000000000..8c35de73c --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/driver.go @@ -0,0 +1,162 @@ +// 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" +) + +// 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) + mc.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 000000000..be014babe --- /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 000000000..760782ff2 --- /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 000000000..e1e2ece4b --- /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 000000000..273cb0ba5 --- /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 000000000..f99934e73 --- /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 = formatBinaryTime(data[pos:pos+int(num)], dstlen) + 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) + } + + 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 000000000..c6438d034 --- /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 000000000..d3b1e2822 --- /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 000000000..ce7fe4cd0 --- /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 000000000..417d72793 --- /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 000000000..cb3650bb9 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils.go @@ -0,0 +1,755 @@ +// 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" + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "io" + "strconv" + "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 = v.Clone() + } + 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 appendMicrosecs(dst, src []byte, decimals int) []byte { + if decimals <= 0 { + return dst + } + if len(src) == 0 { + return append(dst, ".000000"[:decimals+1]...) + } + + 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 { + default: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], digits01[p2], + digits10[p3], digits01[p3], + ) + case 1: + return append(dst, '.', + digits10[p1], + ) + case 2: + return append(dst, '.', + digits10[p1], digits01[p1], + ) + case 3: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], + ) + case 4: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], digits01[p2], + ) + case 5: + return append(dst, '.', + digits10[p1], digits01[p1], + digits10[p2], digits01[p2], + digits10[p3], + ) + } +} + +func formatBinaryDateTime(src []byte, length uint8) (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 { + return zeroDateTime[:length], nil + } + var dst []byte // return value + var p1, p2, p3 byte // current digit pair + + 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 := 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], + ) + return appendMicrosecs(dst, src[2:], int(length)-20), nil +} + +func formatBinaryTime(src []byte, length uint8) (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 { + return zeroDateTime[11 : 11+length], nil + } + var dst []byte // return value + + 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, '-') + } + days := binary.LittleEndian.Uint32(src[1:5]) + hours := int64(days)*24 + int64(src[5]) + + if hours >= 100 { + dst = strconv.AppendInt(dst, hours, 10) + } else { + dst = append(dst, digits10[hours], digits01[hours]) + } + + min, sec := src[6], src[7] + dst = append(dst, ':', + digits10[min], digits01[min], ':', + digits10[sec], digits01[sec], + ) + return appendMicrosecs(dst, src[8:], int(length)-9), 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 +} + +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/AUTHORS b/vendor/github.com/gocql/gocql/AUTHORS new file mode 100644 index 000000000..14cae308b --- /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 000000000..093045a31 --- /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 000000000..3836494a9 --- /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 000000000..6b75cc48a --- /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 000000000..6638bcaa8 --- /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 000000000..67374e925 --- /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 000000000..26853ae7f --- /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 000000000..fb7c3bc90 --- /dev/null +++ b/vendor/github.com/gocql/gocql/conn.go @@ -0,0 +1,1200 @@ +// 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 0, should not be changed concurrently with queries. +// +// depreciated +var TimeoutLimit int64 = 0 + +// 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 000000000..7bfb08754 --- /dev/null +++ b/vendor/github.com/gocql/gocql/connectionpool.go @@ -0,0 +1,579 @@ +// 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 clone to avoid race + return sslOpts.Config.Clone(), 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 000000000..01bd5da8c --- /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 000000000..3af3ae0f3 --- /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 000000000..e94a00ce5 --- /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 000000000..5c4b041a1 --- /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 000000000..b87c6fac0 --- /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 000000000..f7f727bd6 --- /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 000000000..32e6ce66c --- /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 000000000..b09ba8d06 --- /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 000000000..3606f9381 --- /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 000000000..a3c38054e --- /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 000000000..fa9fc6018 --- /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 000000000..120897903 --- /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 000000000..988324c2e --- /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 000000000..c82193cbd --- /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 000000000..77fac8d47 --- /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 000000000..0a614c842 --- /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 000000000..14ca1f433 --- /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 000000000..d006cc0bf --- /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_unsafe.go b/vendor/github.com/gocql/gocql/internal/murmur/murmur_unsafe.go new file mode 100644 index 000000000..501537c77 --- /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 000000000..ea43412aa --- /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 000000000..bd16d4134 --- /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 000000000..fce258f99 --- /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 000000000..db496a6e5 --- /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 000000000..4db4e40c6 --- /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 000000000..3c012a4bb --- /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 000000000..01c8efe1a --- /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 000000000..856afae37 --- /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 000000000..7d810469a --- /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 000000000..bdfcceb98 --- /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 000000000..735dc9dab --- /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 000000000..7ca4c087a --- /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/golang/protobuf/proto/Makefile b/vendor/github.com/golang/protobuf/proto/Makefile deleted file mode 100644 index e2e0651a9..000000000 --- a/vendor/github.com/golang/protobuf/proto/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# 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 --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto - make diff --git a/vendor/github.com/golang/protobuf/proto/clone.go b/vendor/github.com/golang/protobuf/proto/clone.go index e392575b3..3cd3249f7 100644 --- a/vendor/github.com/golang/protobuf/proto/clone.go +++ b/vendor/github.com/golang/protobuf/proto/clone.go @@ -35,22 +35,39 @@ package proto import ( + "fmt" "log" "reflect" "strings" ) // Clone returns a deep copy of a protocol buffer. -func Clone(pb Message) Message { - in := reflect.ValueOf(pb) +func Clone(src Message) Message { + in := reflect.ValueOf(src) if in.IsNil() { - return pb + return src } - 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) + 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. @@ -58,17 +75,24 @@ func Clone(pb Message) Message { // 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() { - // Explicit test prior to mergeStruct so that mistyped nils will fail - panic("proto: type mismatch") + panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src)) } if in.IsNil() { - // Merging nil into non-nil is a quiet no-op + return // Merge from nil src is a noop + } + if m, ok := dst.(generatedMerger); ok { + m.XXX_Merge(src) return } mergeStruct(out.Elem(), in.Elem()) @@ -84,7 +108,7 @@ func mergeStruct(out, in reflect.Value) { mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) } - if emIn, ok := extendable(in.Addr().Interface()); ok { + if emIn, err := extendable(in.Addr().Interface()); err == nil { emOut, _ := extendable(out.Addr().Interface()) mIn, muIn := emIn.extensionsRead() if mIn != nil { diff --git a/vendor/github.com/golang/protobuf/proto/decode.go b/vendor/github.com/golang/protobuf/proto/decode.go index aa207298f..d9aa3c42d 100644 --- a/vendor/github.com/golang/protobuf/proto/decode.go +++ b/vendor/github.com/golang/protobuf/proto/decode.go @@ -39,8 +39,6 @@ import ( "errors" "fmt" "io" - "os" - "reflect" ) // errOverflow is returned when an integer is too large to be represented. @@ -50,10 +48,6 @@ var errOverflow = errors.New("proto: integer overflow") // 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. @@ -267,9 +261,6 @@ func (p *Buffer) DecodeZigzag32() (x uint64, err error) { 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. @@ -311,81 +302,29 @@ func (p *Buffer) DecodeStringBytes() (s string, err error) { 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 +// 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. @@ -395,7 +334,13 @@ type Unmarshaler interface { // to preserve and append to existing data. func Unmarshal(buf []byte, pb Message) error { pb.Reset() - return UnmarshalMerge(buf, pb) + 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 @@ -405,8 +350,16 @@ func Unmarshal(buf []byte, pb Message) error { // 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.(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) @@ -422,12 +375,17 @@ func (p *Buffer) DecodeMessage(pb Message) error { } // 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 { - typ, base, err := getbase(pb) - if err != nil { - return err + b := p.buf[p.index:] + x, y := findEndGroup(b) + if x < 0 { + return io.ErrUnexpectedEOF } - return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base) + err := Unmarshal(b[:x], pb) + p.index += y + return err } // Unmarshal parses the protocol buffer representation in the @@ -438,533 +396,33 @@ func (p *Buffer) DecodeGroup(pb Message) error { // 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 } - 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, _ := 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 - + // 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 000000000..dea2617ce --- /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 index 8b84d1b22..c27d35f86 100644 --- a/vendor/github.com/golang/protobuf/proto/encode.go +++ b/vendor/github.com/golang/protobuf/proto/encode.go @@ -39,7 +39,6 @@ import ( "errors" "fmt" "reflect" - "sort" ) // RequiredNotSetError is the error returned if Marshal is called with @@ -82,10 +81,6 @@ var ( 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 @@ -119,18 +114,27 @@ func (p *Buffer) EncodeVarint(x uint64) error { // 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 - } + 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 n + return 10 } // EncodeFixed64 writes a 64-bit integer to the Buffer. @@ -149,10 +153,6 @@ func (p *Buffer) EncodeFixed64(x uint64) error { 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. @@ -165,20 +165,12 @@ func (p *Buffer) EncodeFixed32(x uint64) error { 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))) + return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } // EncodeZigzag32 writes a zigzag-encoded 32-bit integer @@ -189,10 +181,6 @@ func (p *Buffer) EncodeZigzag32(x uint64) error { 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. @@ -202,11 +190,6 @@ func (p *Buffer) EncodeRawBytes(b []byte) error { 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 { @@ -215,319 +198,17 @@ func (p *Buffer) EncodeStringBytes(s string) error { 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 + siz := Size(pb) + p.EncodeVarint(uint64(siz)) + return p.Marshal(pb) } // All protocol buffer fields are nillable, but be careful. @@ -538,825 +219,3 @@ func isNil(v reflect.Value) bool { } 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/golang/protobuf/proto/equal.go b/vendor/github.com/golang/protobuf/proto/equal.go index 2ed1cf596..d4db5a1c1 100644 --- a/vendor/github.com/golang/protobuf/proto/equal.go +++ b/vendor/github.com/golang/protobuf/proto/equal.go @@ -109,15 +109,6 @@ func equalStruct(v1, v2 reflect.Value) bool { // 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]) { @@ -146,11 +137,7 @@ func equalStruct(v1, v2 reflect.Value) bool { u1 := uf.Bytes() u2 := v2.FieldByName("XXX_unrecognized").Bytes() - if !bytes.Equal(u1, u2) { - return false - } - - return true + return bytes.Equal(u1, u2) } // v1 and v2 are known to have the same type. @@ -261,6 +248,15 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { 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) { @@ -276,8 +272,12 @@ func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { 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) - continue + return false } var err error if m1 == nil { diff --git a/vendor/github.com/golang/protobuf/proto/extensions.go b/vendor/github.com/golang/protobuf/proto/extensions.go index eaad21831..816a3b9d6 100644 --- a/vendor/github.com/golang/protobuf/proto/extensions.go +++ b/vendor/github.com/golang/protobuf/proto/extensions.go @@ -38,6 +38,7 @@ package proto import ( "errors" "fmt" + "io" "reflect" "strconv" "sync" @@ -91,14 +92,29 @@ 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 +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 } - if ep, ok := p.(extendableProtoV1); ok { - return extensionAdapter{ep}, ok - } - return nil, false + // 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. @@ -143,9 +159,6 @@ func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Loc return e.p.extensionMap, &e.p.mu } -var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem() -var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem() - // ExtensionDesc represents an extension specification. // Used in generated code from the protocol compiler. type ExtensionDesc struct { @@ -179,8 +192,8 @@ type Extension struct { // SetRawExtension is for testing only. func SetRawExtension(base Message, id int32, b []byte) { - epb, ok := extendable(base) - if !ok { + epb, err := extendable(base) + if err != nil { return } extmap := epb.extensionsWrite() @@ -205,7 +218,7 @@ func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error { 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()) + return fmt.Errorf("proto: bad extended type; %v does not extend %v", b, a) } // Check the range. if !isExtensionField(pb, extension.Field) { @@ -250,85 +263,11 @@ func extensionProperties(ed *ExtensionDesc) *Properties { 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 { // TODO: Check types, field numbers, etc.? - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return false } extmap, mu := epb.extensionsRead() @@ -336,15 +275,15 @@ func HasExtension(pb Message, extension *ExtensionDesc) bool { return false } mu.Lock() - _, ok = extmap[extension.Field] + _, ok := extmap[extension.Field] mu.Unlock() return ok } // ClearExtension removes the given extension from pb. func ClearExtension(pb Message, extension *ExtensionDesc) { - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return } // TODO: Check types, field numbers, etc.? @@ -352,16 +291,26 @@ func ClearExtension(pb Message, extension *ExtensionDesc) { delete(extmap, extension.Field) } -// GetExtension parses and returns the given extension of pb. -// If the extension is not present and has no default value it returns ErrMissingExtension. +// 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, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return nil, err } - if err := checkExtensionTypes(epb, extension); 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() @@ -388,6 +337,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { 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 @@ -405,6 +359,11 @@ func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) { // 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) @@ -439,31 +398,28 @@ func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) { // 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) + unmarshal := typeUnmarshaler(t, extension.Tag) // 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 }. + // Allocate space to store the pointer/slice. value := reflect.New(t).Elem() + var err error for { - // Discard wire type and field number varint. It isn't needed. - if _, err := o.DecodeVarint(); err != nil { + 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 err := props.dec(o, props, toStructPointer(value.Addr())); err != nil { - return nil, err - } - - if o.index >= len(o.buf) { + if len(b) == 0 { break } } @@ -473,9 +429,9 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) { // 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, ok := extendable(pb) - if !ok { - return nil, errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return nil, err } extensions = make([]interface{}, len(es)) for i, e := range es { @@ -494,9 +450,9 @@ func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, e // 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) + epb, err := extendable(pb) + if err != nil { + return nil, err } registeredExtensions := RegisteredExtensions(pb) @@ -523,9 +479,9 @@ func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) { // SetExtension sets the specified extension of pb to the specified value. func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error { - epb, ok := extendable(pb) - if !ok { - return errors.New("proto: not an extendable proto") + epb, err := extendable(pb) + if err != nil { + return err } if err := checkExtensionTypes(epb, extension); err != nil { return err @@ -550,8 +506,8 @@ func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error // ClearAllExtensions clears all extensions from pb. func ClearAllExtensions(pb Message) { - epb, ok := extendable(pb) - if !ok { + epb, err := extendable(pb) + if err != nil { return } m := epb.extensionsWrite() diff --git a/vendor/github.com/golang/protobuf/proto/lib.go b/vendor/github.com/golang/protobuf/proto/lib.go index 1c225504a..0e2191b8a 100644 --- a/vendor/github.com/golang/protobuf/proto/lib.go +++ b/vendor/github.com/golang/protobuf/proto/lib.go @@ -265,6 +265,7 @@ package proto import ( "encoding/json" + "errors" "fmt" "log" "reflect" @@ -273,6 +274,8 @@ import ( "sync" ) +var errInvalidUTF8 = errors.New("proto: invalid UTF-8 string") + // Message is implemented by generated protocol buffer messages. type Message interface { Reset() @@ -309,16 +312,7 @@ 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 + deterministic bool } // NewBuffer allocates a new Buffer and initializes its internal data to @@ -343,6 +337,30 @@ func (p *Buffer) SetBuf(s []byte) { // 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. */ @@ -831,22 +849,12 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes 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. -// 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()) - }, - } + s := mapKeySorter{vs: vs} - // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps; - // numeric keys are sorted numerically. + // Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps. if len(vs) == 0 { return s } @@ -855,6 +863,12 @@ func mapKeys(vs []reflect.Value) sort.Interface { 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 @@ -895,3 +909,13 @@ 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 index fd982decd..3b6ca41d5 100644 --- a/vendor/github.com/golang/protobuf/proto/message_set.go +++ b/vendor/github.com/golang/protobuf/proto/message_set.go @@ -42,6 +42,7 @@ import ( "fmt" "reflect" "sort" + "sync" ) // errNoMessageTypeID occurs when a protocol buffer does not have a message type ID. @@ -94,10 +95,7 @@ func (ms *messageSet) find(pb Message) *_MessageSet_Item { } func (ms *messageSet) Has(pb Message) bool { - if ms.find(pb) != nil { - return true - } - return false + return ms.find(pb) != nil } func (ms *messageSet) Unmarshal(pb Message) error { @@ -150,46 +148,42 @@ func skipVarint(buf []byte) []byte { // 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 + 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: - if err := encodeExtensions(exts); err != nil { - return nil, err - } - m, _ = exts.extensionsRead() + var u marshalInfo + siz := u.sizeMessageSet(exts) + b := make([]byte, 0, siz) + return u.appendMessageSet(b, exts, deterministic) + case map[int32]Extension: - if err := encodeExtensionsMap(exts); err != nil { - return nil, err + // 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, + }, } - m = 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") } - - // 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. +// 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) { @@ -235,7 +229,15 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { var m map[int32]Extension switch exts := exts.(type) { case *XXX_InternalExtensions: - m, _ = exts.extensionsRead() + 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: @@ -253,15 +255,16 @@ func MarshalMessageSetJSON(exts interface{}) ([]byte, error) { 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 } + + if i > 0 && b.Len() > 1 { + b.WriteByte(',') + } + fmt.Fprintf(&b, `"[%s]":`, msd.name) x := ext.value diff --git a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go index fb512e2e1..b6cad9083 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_reflect.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_reflect.go @@ -29,7 +29,7 @@ // (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 +// +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 @@ -38,32 +38,13 @@ package proto import ( - "math" "reflect" + "sync" ) -// A structPointer is a pointer to a struct. -type structPointer struct { - v reflect.Value -} +const unsafeAllowed = false -// 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. +// 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 @@ -76,409 +57,301 @@ func toField(f *reflect.StructField) field { // 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 } -// 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 { +// 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 } -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)) +// 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)} } -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 +// 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} } -// IsNil reports whether p is nil. -func word32_IsNil(p word32) bool { +// 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() } -// 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() +// 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 { - p.v.SetLen(n + 1) + s.SetLen(n + 1) } else { - t := p.v.Type().Elem() - p.v.Set(reflect.Append(p.v, reflect.Zero(t))) + s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem()))) } - 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))) + 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())) } -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())) +// 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) } - panic("unreachable") + // 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 } -// 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:] +// 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 } - 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()) + // 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)) } - panic("unreachable") + p.v.Elem().Set(slice) +} +func (p pointer) appendInt32Slice(v int32) { + grow(p.v.Elem()).SetInt(int64(v)) } -func structPointer_Word64(p structPointer, f field) word64 { - return word64{structPointer_field(p, f)} +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) } -// word64Val is like word32Val but for 64-bit values. -type word64Val struct { - v reflect.Value +// 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 } -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)) +// 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 } - 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()) + s := reflect.MakeSlice(p.v.Elem().Type(), 0, len(v)) + for _, p := range v { + s = reflect.Append(s, p.v) } - panic("unreachable") + p.v.Elem().Set(s) } -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))) +// 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 word64Slice) Len() int { - return p.v.Len() +func (p pointer) asPointerTo(t reflect.Type) reflect.Value { + // TODO: check that p.v.Type().Elem() == t? + return p.v } -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 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 } -func structPointer_Word64Slice(p structPointer, f field) word64Slice { - return word64Slice{structPointer_field(p, f)} -} +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 index 6b5567d47..d55a335d9 100644 --- a/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go +++ b/vendor/github.com/golang/protobuf/proto/pointer_unsafe.go @@ -29,7 +29,7 @@ // (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 +// +build !purego,!appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. @@ -37,38 +37,13 @@ package proto import ( "reflect" + "sync/atomic" "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. +const unsafeAllowed = true -// 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. +// 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 @@ -80,191 +55,254 @@ func toField(f *reflect.StructField) field { // 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 != ^field(0) + return f != invalidField } -// 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))) +// 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 } -// 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))) +// 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]} } -// 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) +// 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)} } - o.uint32s[0] = x - *p = &o.uint32s[0] - o.uint32s = o.uint32s[1:] + // 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]} } -// Get gets the value pointed at by *v. -func word32_Get(p word32) uint32 { - return **p +// 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())} } -// 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)))) +// 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))} } -// 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 +func (p pointer) isNil() bool { + return p.p == nil } -// Get gets the value pointed at by p. -func word32Val_Get(p word32Val) uint32 { - return *p +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) } -// 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) +// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. +/* + func (p pointer) toInt32Ptr() **int32 { + return (**int32)(p.p) } - o.uint64s[0] = x - *p = &o.uint64s[0] - o.uint64s = o.uint64s[1:] + 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 } -func word64_IsNil(p word64) bool { - return *p == nil +// 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) } -func word64_Get(p word64) uint64 { - return **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 } -func structPointer_Word64(p structPointer, f field) word64 { - return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +// 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) } -// word64Val is like word32Val but for 64-bit values. -type word64Val *uint64 - -func word64Val_Set(p word64Val, o *Buffer, x uint64) { - *p = x +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) } -func word64Val_Get(p word64Val) uint64 { - return *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) } -func structPointer_Word64Val(p structPointer, f field) word64Val { - return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f)))) +// 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 } -// 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))) +// 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 index ec2289c00..f710adab0 100644 --- a/vendor/github.com/golang/protobuf/proto/properties.go +++ b/vendor/github.com/golang/protobuf/proto/properties.go @@ -58,42 +58,6 @@ const ( 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. @@ -140,13 +104,6 @@ type StructProperties struct { 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. @@ -187,36 +144,19 @@ type Properties struct { Default string // default value HasDefault bool // whether an explicit default was provided - def_uint64 uint64 - 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 - sprop *StructProperties // set for struct types only - isMarshaler bool - isUnmarshaler bool + 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 - - 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 += "," s += strconv.Itoa(p.Tag) if p.Required { s += ",req" @@ -262,29 +202,14 @@ func (p *Properties) Parse(s string) { 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 @@ -299,6 +224,7 @@ func (p *Properties) Parse(s string) { return } +outer: for i := 2; i < len(fields); i++ { f := fields[i] switch { @@ -326,229 +252,28 @@ func (p *Properties) Parse(s string) { if i+1 < len(fields) { // Commas aren't escaped, and def is always last. p.Default += "," + strings.Join(fields[i+1:], ",") - break + break outer } } } } -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 - +// 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() { - default: - fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1) - - // proto3 scalar types - - case reflect.Bool: - p.enc = (*Buffer).enc_proto3_bool - p.dec = (*Buffer).dec_proto3_bool - p.size = size_proto3_bool - case reflect.Int32: - p.enc = (*Buffer).enc_proto3_int32 - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_int32 - case reflect.Uint32: - p.enc = (*Buffer).enc_proto3_uint32 - p.dec = (*Buffer).dec_proto3_int32 // can reuse - p.size = size_proto3_uint32 - case reflect.Int64, reflect.Uint64: - p.enc = (*Buffer).enc_proto3_int64 - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.Float32: - p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int32 - p.size = size_proto3_uint32 - case reflect.Float64: - p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits - p.dec = (*Buffer).dec_proto3_int64 - p.size = size_proto3_int64 - case reflect.String: - p.enc = (*Buffer).enc_proto3_string - p.dec = (*Buffer).dec_proto3_string - p.size = size_proto3_string - 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: + if t1.Elem().Kind() == 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 - } + if t2 := t1.Elem(); t2.Kind() == reflect.Ptr && t2.Elem().Kind() == reflect.Struct { + p.stype = t2.Elem() } 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) @@ -562,20 +287,6 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp) } - // 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) @@ -586,32 +297,9 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock } var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() ) -// isMarshaler reports whether type t implements Marshaler. -func isMarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isMarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isMarshaler") - } - return t.Implements(marshalerType) -} - -// isUnmarshaler reports whether type t implements Unmarshaler. -func isUnmarshaler(t reflect.Type) bool { - // We're checking for (likely) pointer-receiver methods - // so if t is not a pointer, something is very wrong. - // The calls above only invoke isUnmarshaler on pointer types. - if t.Kind() != reflect.Ptr { - panic("proto: misuse of isUnmarshaler") - } - 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) @@ -621,14 +309,11 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF // "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) + p.setFieldProps(typ, f, lockGetProp) } var ( @@ -678,9 +363,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { propertiesMap[t] = prop // build properties - prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) || - reflect.PtrTo(t).Implements(extendableProtoV1Type) - prop.unrecField = invalidField prop.Prop = make([]*Properties, t.NumField()) prop.order = make([]int, t.NumField()) @@ -690,17 +372,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { 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 - 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 != "" { // Oneof fields don't use the traditional protobuf tag. @@ -715,9 +386,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } 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. @@ -728,8 +396,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { } if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok { var oots []interface{} - prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs() - prop.stype = t + _, _, _, oots = om.XXX_OneofFuncs() // Interpret oneof metadata. prop.OneofTypes = make(map[string]*OneofProperties) @@ -779,30 +446,6 @@ func getPropertiesLocked(t reflect.Type) *StructProperties { 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. @@ -826,20 +469,42 @@ func EnumValueMap(enumType string) map[string]int32 { // 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) + 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 := protoTypes[name]; ok { + 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) - protoTypes[name] = t + 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 } @@ -855,7 +520,14 @@ func MessageName(x Message) string { } // MessageType returns the message type (pointer to struct) for a named message. -func MessageType(name string) reflect.Type { return protoTypes[name] } +// 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 ( 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 000000000..0f212b302 --- /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 000000000..5525def6a --- /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 000000000..55f0340a3 --- /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 index 965876bf0..2205fdaad 100644 --- a/vendor/github.com/golang/protobuf/proto/text.go +++ b/vendor/github.com/golang/protobuf/proto/text.go @@ -50,7 +50,6 @@ import ( var ( newline = []byte("\n") spaces = []byte(" ") - gtNewline = []byte(">\n") endBraceNewline = []byte("}\n") backslashN = []byte{'\\', 'n'} backslashR = []byte{'\\', 'r'} @@ -170,11 +169,6 @@ func writeName(w *textWriter, props *Properties) error { 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 { @@ -269,6 +263,10 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { 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 @@ -436,12 +434,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { return err } } - if b, ok := fv.Interface().(raw); ok { - if err := writeRaw(w, b.Bytes()); err != nil { - return err - } - continue - } // Enums have a String method, so writeAny will work fine. if err := tm.writeAny(w, fv, props); err != nil { @@ -455,7 +447,7 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { // Extensions (the XXX_extensions field). pv := sv.Addr() - if _, ok := extendable(pv.Interface()); ok { + if _, err := extendable(pv.Interface()); err == nil { if err := tm.writeExtensions(w, pv); err != nil { return err } @@ -464,27 +456,6 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error { 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) @@ -535,6 +506,19 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert } } 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 { @@ -543,8 +527,13 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert if _, err = w.Write(text); err != nil { return err } - } else if err := tm.writeStruct(w, v); 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 { diff --git a/vendor/github.com/golang/protobuf/proto/text_parser.go b/vendor/github.com/golang/protobuf/proto/text_parser.go index 5e14513f2..0685bae36 100644 --- a/vendor/github.com/golang/protobuf/proto/text_parser.go +++ b/vendor/github.com/golang/protobuf/proto/text_parser.go @@ -206,7 +206,6 @@ func (p *textParser) advance() { var ( errBadUTF8 = errors.New("proto: bad UTF-8") - errBadHex = errors.New("proto: bad hexadecimal") ) func unquoteC(s string, quote rune) (string, error) { @@ -277,60 +276,47 @@ func unescape(s string) (ch string, tail string, err error) { return "?", s, nil // trigraph workaround case '\'', '"', '\\': return string(r), s, nil - case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X': + case '0', '1', '2', '3', '4', '5', '6', '7': if len(s) < 2 { return "", "", fmt.Errorf(`\%c requires 2 following digits`, r) } - base := 8 - ss := s[:2] + ss := string(r) + s[:2] s = s[2:] - if r == 'x' || r == 'X' { - base = 16 - } else { - ss = string(r) + ss - } - i, err := strconv.ParseUint(ss, base, 8) + i, err := strconv.ParseUint(ss, 8, 8) if err != nil { - return "", "", err + return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss) } return string([]byte{byte(i)}), s, nil - case 'u', 'U': - n := 4 - if r == 'U' { + 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 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 + return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n) } + ss := s[:n] s = s[n:] - return string(bs), s, nil + 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) } -// 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 } @@ -728,6 +714,9 @@ func (p *textParser) consumeExtName() (string, error) { 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 } @@ -865,7 +854,7 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { return p.readStruct(fv, terminator) case reflect.Uint32: if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil { - fv.SetUint(x) + fv.SetUint(uint64(x)) return nil } case reflect.Uint64: @@ -883,13 +872,9 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error { // UnmarshalText returns *RequiredNotSetError. func UnmarshalText(s string, pb Message) error { if um, ok := pb.(encoding.TextUnmarshaler); ok { - err := um.UnmarshalText([]byte(s)) - return err + return um.UnmarshalText([]byte(s)) } pb.Reset() v := reflect.ValueOf(pb) - if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil { - return pe - } - return nil + return newTextParser(s).readStruct(v.Elem(), "") } diff --git a/vendor/github.com/golang/snappy/AUTHORS b/vendor/github.com/golang/snappy/AUTHORS new file mode 100644 index 000000000..bcfa19520 --- /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 000000000..931ae3160 --- /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 000000000..6050c10f4 --- /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 000000000..cea12879a --- /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 000000000..72efb0353 --- /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 000000000..fcd192b84 --- /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 000000000..e6179f65e --- /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 000000000..8c9f2049b --- /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 000000000..8d393e904 --- /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 000000000..150d91bc8 --- /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 000000000..adfd979fe --- /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 000000000..dbcae905e --- /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 000000000..ece692ea4 --- /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/hailocab/go-hostpool/LICENSE b/vendor/github.com/hailocab/go-hostpool/LICENSE new file mode 100644 index 000000000..f24db89c4 --- /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 000000000..7f4437277 --- /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 000000000..8627aa5cd --- /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 000000000..9bc3102a9 --- /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 000000000..dcec9a0b7 --- /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 000000000..702ca9276 --- /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/go-hclog/LICENSE b/vendor/github.com/hashicorp/go-hclog/LICENSE new file mode 100644 index 000000000..abaf1e45f --- /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 000000000..1153e2853 --- /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 000000000..55ce43960 --- /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 000000000..0166c3dd2 --- /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 000000000..362924887 --- /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 000000000..c10ce6e88 --- /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 000000000..8af1a3be4 --- /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 000000000..2bb927fc9 --- /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-plugin/LICENSE b/vendor/github.com/hashicorp/go-plugin/LICENSE new file mode 100644 index 000000000..82b4de97c --- /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 000000000..e4558dbc5 --- /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 000000000..fce0614f1 --- /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 000000000..d22c566ed --- /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 000000000..22a7baa6a --- /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 000000000..49fd21c61 --- /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 000000000..d490dafba --- /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 000000000..f57834856 --- /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 000000000..44294d0d3 --- /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 000000000..3a727393c --- /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 000000000..2996c14c3 --- /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 000000000..01c45ad7c --- /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 000000000..79d967463 --- /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 000000000..88c999a58 --- /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 000000000..70ba546bf --- /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 000000000..9f7b01809 --- /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 000000000..0cfc19e52 --- /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 000000000..f30a4b1d3 --- /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 000000000..5bb18dd5d --- /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 000000000..1e808b99e --- /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 000000000..033079ea0 --- /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 000000000..1d547aaaa --- /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 000000000..2f541d968 --- /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/README.md b/vendor/github.com/hashicorp/go-retryablehttp/README.md index 0d6f9ed40..ccdc7e87c 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/README.md +++ b/vendor/github.com/hashicorp/go-retryablehttp/README.md @@ -14,13 +14,16 @@ 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, then a retry is invoked after a wait period. -Otherwise, the response is returned and left to the caller to interpret. +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) require an `io.ReadSeeker` to be provided. This enables the -request body to be "rewound" if the initial request fails so that the full -request can be attempted again. +(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 =========== diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go index 2ecd1ae88..c016939a1 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/client.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -8,18 +8,27 @@ // response is received, then a retry is invoked. 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) require an io.ReadSeeker to be provided. This enables the -// request body to be "rewound" if the initial request fails so that the full -// request can be attempted again. +// 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" @@ -44,6 +53,9 @@ var ( 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 { @@ -54,7 +66,7 @@ type LenReader interface { 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 io.ReadSeeker + body ReaderFunc // Embed an HTTP request directly. This makes a *Request act exactly // like an *http.Request so that all meta methods are supported. @@ -62,24 +74,103 @@ type Request struct { } // NewRequest creates a new wrapped request. -func NewRequest(method, url string, body io.ReadSeeker) (*Request, error) { - // Wrap the body in a noop ReadCloser if non-nil. This prevents the - // reader from being closed by the HTTP client. - var rcBody io.ReadCloser - if body != nil { - rcBody = ioutil.NopCloser(body) +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) + } } - // Make the request with the noop-closer for the body. - httpReq, err := http.NewRequest(method, url, rcBody) + httpReq, err := http.NewRequest(method, url, nil) if err != nil { return nil, err } - - // Check if we can set the Content-Length automatically. - if lr, ok := body.(LenReader); ok { - httpReq.ContentLength = int64(lr.Len()) - } + httpReq.ContentLength = contentLength return &Request{body, httpReq}, nil } @@ -112,6 +203,12 @@ type CheckRetry func(resp *http.Response, err error) (bool, error) // 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 { @@ -136,6 +233,9 @@ type Client struct { // 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. @@ -161,7 +261,7 @@ func DefaultRetryPolicy(resp *http.Response, err error) (bool, error) { // 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 { + if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) { return true, nil } @@ -180,17 +280,73 @@ func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) 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) { - c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL) + 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 { - if _, err := req.body.Seek(0, 0); err != nil { - return nil, fmt.Errorf("failed to seek body: %v", err) + 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) } } @@ -199,13 +355,18 @@ func (c *Client) Do(req *Request) (*http.Response, error) { } // Attempt the request - resp, err := c.HTTPClient.Do(req.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 { - c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err) + 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. @@ -223,25 +384,38 @@ func (c *Client) Do(req *Request) (*http.Response, error) { 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 { + if err == nil && resp != nil { c.drainBody(resp.Body) } - remain := c.RetryMax - i - if remain == 0 { - break - } 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) } - c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) + if c.Logger != nil { + c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) + } time.Sleep(wait) } - // Return an error if we fall out of the retry loop + 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) } @@ -251,7 +425,9 @@ func (c *Client) drainBody(body io.ReadCloser) { defer body.Close() _, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit)) if err != nil { - c.Logger.Printf("[ERR] error reading response body: %v", err) + if c.Logger != nil { + c.Logger.Printf("[ERR] error reading response body: %v", err) + } } } @@ -284,12 +460,12 @@ func (c *Client) Head(url string) (*http.Response, error) { } // Post is a shortcut for doing a POST request without making a new client. -func Post(url, bodyType string, body io.ReadSeeker) (*http.Response, error) { +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 io.ReadSeeker) (*http.Response, error) { +func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) { req, err := NewRequest("POST", url, body) if err != nil { return nil, err diff --git a/vendor/github.com/hashicorp/vault/LICENSE b/vendor/github.com/hashicorp/vault/LICENSE new file mode 100644 index 000000000..e87a115e4 --- /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 000000000..da870c111 --- /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 000000000..4f74f61fe --- /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 000000000..8f0d3f86e --- /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 000000000..b9ae100bc --- /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 000000000..346a71193 --- /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 000000000..1d37a1938 --- /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 000000000..5bcff8c6c --- /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 000000000..053a27723 --- /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 000000000..b6517c44a --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/secret.go @@ -0,0 +1,308 @@ +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. It +// also populates the secret's Auth info with identity/token policy info. +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 + } + + var tokenPolicies []string + + // Token policies + { + _, ok := s.Data["policies"] + if !ok { + goto TOKEN_DONE + } + + sList, ok := s.Data["policies"].([]string) + if ok { + tokenPolicies = sList + goto TOKEN_DONE + } + + list, ok := s.Data["policies"].([]interface{}) + if !ok { + return nil, fmt.Errorf("unable to convert token policies to expected format") + } + for _, v := range list { + p, ok := v.(string) + if !ok { + return nil, fmt.Errorf("unable to convert policy %v to string", v) + } + tokenPolicies = append(tokenPolicies, p) + } + } + +TOKEN_DONE: + var identityPolicies []string + + // Identity policies + { + _, ok := s.Data["identity_policies"] + if !ok { + goto DONE + } + + sList, ok := s.Data["identity_policies"].([]string) + if ok { + identityPolicies = sList + goto DONE + } + + list, ok := s.Data["identity_policies"].([]interface{}) + if !ok { + return nil, fmt.Errorf("unable to convert identity policies to expected format") + } + for _, v := range list { + p, ok := v.(string) + if !ok { + return nil, fmt.Errorf("unable to convert policy %v to string", v) + } + identityPolicies = append(identityPolicies, p) + } + } + +DONE: + + if s.Auth == nil { + s.Auth = &SecretAuth{} + } + + policies := append(tokenPolicies, identityPolicies...) + + s.Auth.TokenPolicies = tokenPolicies + s.Auth.IdentityPolicies = identityPolicies + s.Auth.Policies = policies + + 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"` + TokenPolicies []string `json:"token_policies"` + IdentityPolicies []string `json:"identity_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 000000000..a17b0eb23 --- /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 000000000..032fb436c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/api/ssh_agent.go @@ -0,0 +1,231 @@ +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/hashicorp/vault/helper/hclutil" + "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 := hclutil.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 +} 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 000000000..5fb111887 --- /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 000000000..05cd756d4 --- /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 000000000..0b1a319c7 --- /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 000000000..cbb3a72d7 --- /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 000000000..e7f2a5945 --- /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 000000000..adb5496d4 --- /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 000000000..82fd1f6f9 --- /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 000000000..f824ab7dd --- /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 000000000..4951c46e1 --- /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 000000000..34bd99e65 --- /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 000000000..8ac5b455a --- /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 000000000..8183b10f5 --- /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 000000000..9c9d9c08b --- /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 000000000..ddeac0166 --- /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 000000000..8108dced8 --- /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 000000000..3d594baf9 --- /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 000000000..421e5f19f --- /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 000000000..fed703350 --- /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 000000000..55970ec36 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/audit/format.go @@ -0,0 +1,454 @@ +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, + TokenPolicies: auth.TokenPolicies, + IdentityPolicies: auth.IdentityPolicies, + 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, + TokenPolicies: resp.Auth.TokenPolicies, + IdentityPolicies: resp.Auth.IdentityPolicies, + 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, + TokenPolicies: auth.TokenPolicies, + IdentityPolicies: auth.IdentityPolicies, + 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"` + TokenPolicies []string `json:"token_policies,omitempty"` + IdentityPolicies []string `json:"identity_policies,omitempty"` + 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 000000000..f42ab20d3 --- /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 000000000..30937464d --- /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 000000000..7702a1ee5 --- /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 000000000..be1aad97e --- /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/logical/database/dbplugin/client.go b/vendor/github.com/hashicorp/vault/builtin/logical/database/dbplugin/client.go new file mode 100644 index 000000000..37cb629c4 --- /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 000000000..3c5bb984d --- /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 000000000..7873792ee --- /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 000000000..ba2dd4e5c --- /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 000000000..1b5267e8f --- /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 000000000..25cbc9796 --- /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 000000000..502f97ebc --- /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 000000000..656c44b2d --- /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/builtin/logical/pki/backend.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/backend.go new file mode 100644 index 000000000..60e943acb --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/backend.go @@ -0,0 +1,108 @@ +package pki + +import ( + "context" + "strings" + "sync" + "time" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// Factory creates a new backend implementing the logical.Backend interface +func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) { + b := Backend(conf) + if err := b.Setup(ctx, conf); err != nil { + return nil, err + } + return b, nil +} + +// Backend returns a new Backend framework struct +func Backend(conf *logical.BackendConfig) *backend { + var b backend + b.Backend = &framework.Backend{ + Help: strings.TrimSpace(backendHelp), + + PathsSpecial: &logical.Paths{ + Unauthenticated: []string{ + "cert/*", + "ca/pem", + "ca_chain", + "ca", + "crl/pem", + "crl", + }, + + LocalStorage: []string{ + "revoked/", + "crl", + "certs/", + }, + + Root: []string{ + "root", + "root/sign-self-issued", + }, + + SealWrapStorage: []string{ + "config/ca_bundle", + }, + }, + + Paths: []*framework.Path{ + pathListRoles(&b), + pathRoles(&b), + pathGenerateRoot(&b), + pathSignIntermediate(&b), + pathSignSelfIssued(&b), + pathDeleteRoot(&b), + pathGenerateIntermediate(&b), + pathSetSignedIntermediate(&b), + pathConfigCA(&b), + pathConfigCRL(&b), + pathConfigURLs(&b), + pathSignVerbatim(&b), + pathSign(&b), + pathIssue(&b), + pathRotateCRL(&b), + pathFetchCA(&b), + pathFetchCAChain(&b), + pathFetchCRL(&b), + pathFetchCRLViaCertPath(&b), + pathFetchValid(&b), + pathFetchListCerts(&b), + pathRevoke(&b), + pathTidy(&b), + }, + + Secrets: []*framework.Secret{ + secretCerts(&b), + }, + + BackendType: logical.TypeLogical, + } + + b.crlLifetime = time.Hour * 72 + b.tidyCASGuard = new(uint32) + b.storage = conf.StorageView + + return &b +} + +type backend struct { + *framework.Backend + + storage logical.Storage + crlLifetime time.Duration + revokeStorageLock sync.RWMutex + tidyCASGuard *uint32 +} + +const backendHelp = ` +The PKI backend dynamically generates X509 server and client certificates. + +After mounting this backend, configure the CA using the "pem_bundle" endpoint within +the "config/" path. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/ca_util.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/ca_util.go new file mode 100644 index 000000000..143fd574e --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/ca_util.go @@ -0,0 +1,58 @@ +package pki + +import ( + "time" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func (b *backend) getGenerationParams( + data *framework.FieldData, +) (exported bool, format string, role *roleEntry, errorResp *logical.Response) { + exportedStr := data.Get("exported").(string) + switch exportedStr { + case "exported": + exported = true + case "internal": + default: + errorResp = logical.ErrorResponse( + `the "exported" path parameter must be "internal" or "exported"`) + return + } + + format = getFormat(data) + if format == "" { + errorResp = logical.ErrorResponse( + `the "format" path parameter must be "pem", "der", "der_pkcs", or "pem_bundle"`) + return + } + + role = &roleEntry{ + TTL: time.Duration(data.Get("ttl").(int)) * time.Second, + KeyType: data.Get("key_type").(string), + KeyBits: data.Get("key_bits").(int), + AllowLocalhost: true, + AllowAnyName: true, + AllowIPSANs: true, + EnforceHostnames: false, + AllowedURISANs: []string{"*"}, + AllowedSerialNumbers: []string{"*"}, + OU: data.Get("ou").([]string), + Organization: data.Get("organization").([]string), + Country: data.Get("country").([]string), + Locality: data.Get("locality").([]string), + Province: data.Get("province").([]string), + StreetAddress: data.Get("street_address").([]string), + PostalCode: data.Get("postal_code").([]string), + } + + if role.KeyType == "rsa" && role.KeyBits < 2048 { + errorResp = logical.ErrorResponse("RSA keys < 2048 bits are unsafe and not supported") + return + } + + errorResp = validateKeyTypeLength(role.KeyType, role.KeyBits) + + return +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/cert_util.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/cert_util.go new file mode 100644 index 000000000..f6dc67a9b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/cert_util.go @@ -0,0 +1,1691 @@ +package pki + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/base64" + "encoding/pem" + "fmt" + "net" + "net/url" + "regexp" + "strconv" + "strings" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/certutil" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/helper/strutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" + "github.com/ryanuber/go-glob" + "golang.org/x/crypto/cryptobyte" + cbbasn1 "golang.org/x/crypto/cryptobyte/asn1" + "golang.org/x/net/idna" +) + +type certExtKeyUsage int + +const ( + anyExtKeyUsage certExtKeyUsage = 1 << iota + serverAuthExtKeyUsage + clientAuthExtKeyUsage + codeSigningExtKeyUsage + emailProtectionExtKeyUsage + ipsecEndSystemExtKeyUsage + ipsecTunnelExtKeyUsage + ipsecUserExtKeyUsage + timeStampingExtKeyUsage + ocspSigningExtKeyUsage + microsoftServerGatedCryptoExtKeyUsage + netscapeServerGatedCryptoExtKeyUsage + microsoftCommercialCodeSigningExtKeyUsage + microsoftKernelCodeSigningExtKeyUsage +) + +type dataBundle struct { + params *creationParameters + signingBundle *caInfoBundle + csr *x509.CertificateRequest + role *roleEntry + req *logical.Request + apiData *framework.FieldData +} + +type creationParameters struct { + Subject pkix.Name + DNSNames []string + EmailAddresses []string + IPAddresses []net.IP + URIs []*url.URL + OtherSANs map[string][]string + IsCA bool + KeyType string + KeyBits int + NotAfter time.Time + KeyUsage x509.KeyUsage + ExtKeyUsage certExtKeyUsage + ExtKeyUsageOIDs []string + PolicyIdentifiers []string + BasicConstraintsValidForNonCA bool + + // Only used when signing a CA cert + UseCSRValues bool + PermittedDNSDomains []string + + // URLs to encode into the certificate + URLs *urlEntries + + // The maximum path length to encode + MaxPathLength int +} + +type caInfoBundle struct { + certutil.ParsedCertBundle + URLs *urlEntries +} + +func (b *caInfoBundle) GetCAChain() []*certutil.CertBlock { + chain := []*certutil.CertBlock{} + + // Include issuing CA in Chain, not including Root Authority + if (len(b.Certificate.AuthorityKeyId) > 0 && + !bytes.Equal(b.Certificate.AuthorityKeyId, b.Certificate.SubjectKeyId)) || + (len(b.Certificate.AuthorityKeyId) == 0 && + !bytes.Equal(b.Certificate.RawIssuer, b.Certificate.RawSubject)) { + + chain = append(chain, &certutil.CertBlock{ + Certificate: b.Certificate, + Bytes: b.CertificateBytes, + }) + if b.CAChain != nil && len(b.CAChain) > 0 { + chain = append(chain, b.CAChain...) + } + } + + return chain +} + +var ( + // A note on hostnameRegex: although we set the StrictDomainName option + // when doing the idna conversion, this appears to only affect output, not + // input, so it will allow e.g. host^123.example.com straight through. So + // we still need to use this to check the output. + hostnameRegex = regexp.MustCompile(`^(\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) + oidExtensionBasicConstraints = []int{2, 5, 29, 19} +) + +func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool { + for _, e := range extensions { + if e.Id.Equal(oid) { + return true + } + } + return false +} + +func getFormat(data *framework.FieldData) string { + format := data.Get("format").(string) + switch format { + case "pem": + case "der": + case "pem_bundle": + default: + format = "" + } + return format +} + +func validateKeyTypeLength(keyType string, keyBits int) *logical.Response { + switch keyType { + case "rsa": + switch keyBits { + case 2048: + case 4096: + case 8192: + default: + return logical.ErrorResponse(fmt.Sprintf( + "unsupported bit length for RSA key: %d", keyBits)) + } + case "ec": + switch keyBits { + case 224: + case 256: + case 384: + case 521: + default: + return logical.ErrorResponse(fmt.Sprintf( + "unsupported bit length for EC key: %d", keyBits)) + } + case "any": + default: + return logical.ErrorResponse(fmt.Sprintf( + "unknown key type %s", keyType)) + } + + return nil +} + +// Fetches the CA info. Unlike other certificates, the CA info is stored +// in the backend as a CertBundle, because we are storing its private key +func fetchCAInfo(ctx context.Context, req *logical.Request) (*caInfoBundle, error) { + bundleEntry, err := req.Storage.Get(ctx, "config/ca_bundle") + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to fetch local CA certificate/key: %v", err)} + } + if bundleEntry == nil { + return nil, errutil.UserError{Err: "backend must be configured with a CA certificate/key"} + } + + var bundle certutil.CertBundle + if err := bundleEntry.DecodeJSON(&bundle); err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to decode local CA certificate/key: %v", err)} + } + + parsedBundle, err := bundle.ToParsedCertBundle() + if err != nil { + return nil, errutil.InternalError{Err: err.Error()} + } + + if parsedBundle.Certificate == nil { + return nil, errutil.InternalError{Err: "stored CA information not able to be parsed"} + } + + caInfo := &caInfoBundle{*parsedBundle, nil} + + entries, err := getURLs(ctx, req) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to fetch URL information: %v", err)} + } + if entries == nil { + entries = &urlEntries{ + IssuingCertificates: []string{}, + CRLDistributionPoints: []string{}, + OCSPServers: []string{}, + } + } + caInfo.URLs = entries + + return caInfo, nil +} + +// Allows fetching certificates from the backend; it handles the slightly +// separate pathing for CA, CRL, and revoked certificates. +func fetchCertBySerial(ctx context.Context, req *logical.Request, prefix, serial string) (*logical.StorageEntry, error) { + var path, legacyPath string + var err error + var certEntry *logical.StorageEntry + + hyphenSerial := normalizeSerial(serial) + colonSerial := strings.Replace(strings.ToLower(serial), "-", ":", -1) + + switch { + // Revoked goes first as otherwise ca/crl get hardcoded paths which fail if + // we actually want revocation info + case strings.HasPrefix(prefix, "revoked/"): + legacyPath = "revoked/" + colonSerial + path = "revoked/" + hyphenSerial + case serial == "ca": + path = "ca" + case serial == "crl": + path = "crl" + default: + legacyPath = "certs/" + colonSerial + path = "certs/" + hyphenSerial + } + + certEntry, err = req.Storage.Get(ctx, path) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error fetching certificate %s: %s", serial, err)} + } + if certEntry != nil { + if certEntry.Value == nil || len(certEntry.Value) == 0 { + return nil, errutil.InternalError{Err: fmt.Sprintf("returned certificate bytes for serial %s were empty", serial)} + } + return certEntry, nil + } + + // If legacyPath is unset, it's going to be a CA or CRL; return immediately + if legacyPath == "" { + return nil, nil + } + + // Retrieve the old-style path + certEntry, err = req.Storage.Get(ctx, legacyPath) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error fetching certificate %s: %s", serial, err)} + } + if certEntry == nil { + return nil, nil + } + if certEntry.Value == nil || len(certEntry.Value) == 0 { + return nil, errutil.InternalError{Err: fmt.Sprintf("returned certificate bytes for serial %s were empty", serial)} + } + + // Update old-style paths to new-style paths + certEntry.Key = path + if err = req.Storage.Put(ctx, certEntry); err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error saving certificate with serial %s to new location", serial)} + } + if err = req.Storage.Delete(ctx, legacyPath); err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error deleting certificate with serial %s from old location", serial)} + } + + return certEntry, nil +} + +// Given a set of requested names for a certificate, verifies that all of them +// match the various toggles set in the role for controlling issuance. +// If one does not pass, it is returned in the string argument. +func validateNames(data *dataBundle, names []string) string { + for _, name := range names { + sanitizedName := name + emailDomain := name + isEmail := false + isWildcard := false + + // If it has an @, assume it is an email address and separate out the + // user from the hostname portion so that we can act on the hostname. + // Note that this matches behavior from the alt_names parameter. If it + // ends up being problematic for users, I guess that could be separated + // into dns_names and email_names in the future to be explicit, but I + // don't think this is likely. + if strings.Contains(name, "@") { + splitEmail := strings.Split(name, "@") + if len(splitEmail) != 2 { + return name + } + sanitizedName = splitEmail[1] + emailDomain = splitEmail[1] + isEmail = true + } + + // If we have an asterisk as the first part of the domain name, mark it + // as wildcard and set the sanitized name to the remainder of the + // domain + if strings.HasPrefix(sanitizedName, "*.") { + sanitizedName = sanitizedName[2:] + isWildcard = true + } + + // Email addresses using wildcard domain names do not make sense + if isEmail && isWildcard { + return name + } + + // AllowAnyName is checked after this because EnforceHostnames still + // applies when allowing any name. Also, we check the sanitized name to + // ensure that we are not either checking a full email address or a + // wildcard prefix. + if data.role.EnforceHostnames { + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToASCII(sanitizedName) + if err != nil { + return name + } + if !hostnameRegex.MatchString(converted) { + return name + } + } + + // Self-explanatory + if data.role.AllowAnyName { + continue + } + + // The following blocks all work the same basic way: + // 1) If a role allows a certain class of base (localhost, token + // display name, role-configured domains), perform further tests + // + // 2) If there is a perfect match on either the name itself or it's an + // email address with a perfect match on the hostname portion, allow it + // + // 3) If subdomains are allowed, we check based on the sanitized name; + // note that if not a wildcard, will be equivalent to the email domain + // for email checks, and we already checked above for both a wildcard + // and email address being present in the same name + // 3a) First we check for a non-wildcard subdomain, as in . + // 3b) Then we check if it's a wildcard and the base domain is a match + // + // Variances are noted in-line + + if data.role.AllowLocalhost { + if name == "localhost" || + name == "localdomain" || + (isEmail && emailDomain == "localhost") || + (isEmail && emailDomain == "localdomain") { + continue + } + + if data.role.AllowSubdomains { + // It is possible, if unlikely, to have a subdomain of "localhost" + if strings.HasSuffix(sanitizedName, ".localhost") || + (isWildcard && sanitizedName == "localhost") { + continue + } + + // A subdomain of "localdomain" is also not entirely uncommon + if strings.HasSuffix(sanitizedName, ".localdomain") || + (isWildcard && sanitizedName == "localdomain") { + continue + } + } + } + + if data.role.AllowTokenDisplayName { + if name == data.req.DisplayName { + continue + } + + if data.role.AllowSubdomains { + if isEmail { + // If it's an email address, we need to parse the token + // display name in order to do a proper comparison of the + // subdomain + if strings.Contains(data.req.DisplayName, "@") { + splitDisplay := strings.Split(data.req.DisplayName, "@") + if len(splitDisplay) == 2 { + // Compare the sanitized name against the hostname + // portion of the email address in the broken + // display name + if strings.HasSuffix(sanitizedName, "."+splitDisplay[1]) { + continue + } + } + } + } + + if strings.HasSuffix(sanitizedName, "."+data.req.DisplayName) || + (isWildcard && sanitizedName == data.req.DisplayName) { + continue + } + } + } + + if len(data.role.AllowedDomains) > 0 { + valid := false + for _, currDomain := range data.role.AllowedDomains { + // If there is, say, a trailing comma, ignore it + if currDomain == "" { + continue + } + + // First, allow an exact match of the base domain if that role flag + // is enabled + if data.role.AllowBareDomains && + (name == currDomain || + (isEmail && emailDomain == currDomain)) { + valid = true + break + } + + if data.role.AllowSubdomains { + if strings.HasSuffix(sanitizedName, "."+currDomain) || + (isWildcard && sanitizedName == currDomain) { + valid = true + break + } + } + + if data.role.AllowGlobDomains && + strings.Contains(currDomain, "*") && + glob.Glob(currDomain, name) { + valid = true + break + } + } + if valid { + continue + } + } + + return name + } + + return "" +} + +// validateOtherSANs checks if the values requested are allowed. If an OID +// isn't allowed, it will be returned as the first string. If a value isn't +// allowed, it will be returned as the second string. Empty strings + error +// means everything is okay. +func validateOtherSANs(data *dataBundle, requested map[string][]string) (string, string, error) { + allowed, err := parseOtherSANs(data.role.AllowedOtherSANs) + if err != nil { + return "", "", errwrap.Wrapf("error parsing role's allowed SANs: {{err}}", err) + } + for oid, names := range requested { + for _, name := range names { + allowedNames, ok := allowed[oid] + if !ok { + return oid, "", nil + } + + valid := false + for _, allowedName := range allowedNames { + if glob.Glob(allowedName, name) { + valid = true + break + } + } + + if !valid { + return oid, name, nil + } + } + } + + return "", "", nil +} + +func parseOtherSANs(others []string) (map[string][]string, error) { + result := map[string][]string{} + for _, other := range others { + splitOther := strings.SplitN(other, ";", 2) + if len(splitOther) != 2 { + return nil, fmt.Errorf("expected a semicolon in other SAN %q", other) + } + splitType := strings.SplitN(splitOther[1], ":", 2) + if len(splitType) != 2 { + return nil, fmt.Errorf("expected a colon in other SAN %q", other) + } + if strings.ToLower(splitType[0]) != "utf8" { + return nil, fmt.Errorf("only utf8 other SANs are supported; found non-supported type in other SAN %q", other) + } + result[splitOther[0]] = append(result[splitOther[0]], splitType[1]) + } + + return result, nil +} + +func validateSerialNumber(data *dataBundle, serialNumber string) string { + valid := false + if len(data.role.AllowedSerialNumbers) > 0 { + for _, currSerialNumber := range data.role.AllowedSerialNumbers { + if currSerialNumber == "" { + continue + } + + if (strings.Contains(currSerialNumber, "*") && + glob.Glob(currSerialNumber, serialNumber)) || + currSerialNumber == serialNumber { + valid = true + break + } + } + } + if !valid { + return serialNumber + } else { + return "" + } +} + +func generateCert(ctx context.Context, + b *backend, + data *dataBundle, + isCA bool) (*certutil.ParsedCertBundle, error) { + + if data.role == nil { + return nil, errutil.InternalError{Err: "no role found in data bundle"} + } + + if data.role.KeyType == "rsa" && data.role.KeyBits < 2048 { + return nil, errutil.UserError{Err: "RSA keys < 2048 bits are unsafe and not supported"} + } + + err := generateCreationBundle(b, data) + if err != nil { + return nil, err + } + if data.params == nil { + return nil, errutil.InternalError{Err: "nil parameters received from parameter bundle generation"} + } + + if isCA { + data.params.IsCA = isCA + + data.params.PermittedDNSDomains = data.apiData.Get("permitted_dns_domains").([]string) + + if data.signingBundle == nil { + // Generating a self-signed root certificate + entries, err := getURLs(ctx, data.req) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to fetch URL information: %v", err)} + } + if entries == nil { + entries = &urlEntries{ + IssuingCertificates: []string{}, + CRLDistributionPoints: []string{}, + OCSPServers: []string{}, + } + } + data.params.URLs = entries + + if data.role.MaxPathLength == nil { + data.params.MaxPathLength = -1 + } else { + data.params.MaxPathLength = *data.role.MaxPathLength + } + } + } + + parsedBundle, err := createCertificate(data) + if err != nil { + return nil, err + } + + return parsedBundle, nil +} + +// N.B.: This is only meant to be used for generating intermediate CAs. +// It skips some sanity checks. +func generateIntermediateCSR(b *backend, data *dataBundle) (*certutil.ParsedCSRBundle, error) { + err := generateCreationBundle(b, data) + if err != nil { + return nil, err + } + if data.params == nil { + return nil, errutil.InternalError{Err: "nil parameters received from parameter bundle generation"} + } + + parsedBundle, err := createCSR(data) + if err != nil { + return nil, err + } + + return parsedBundle, nil +} + +func signCert(b *backend, + data *dataBundle, + isCA bool, + useCSRValues bool) (*certutil.ParsedCertBundle, error) { + + if data.role == nil { + return nil, errutil.InternalError{Err: "no role found in data bundle"} + } + + csrString := data.apiData.Get("csr").(string) + if csrString == "" { + return nil, errutil.UserError{Err: fmt.Sprintf("\"csr\" is empty")} + } + + pemBytes := []byte(csrString) + pemBlock, pemBytes := pem.Decode(pemBytes) + if pemBlock == nil { + return nil, errutil.UserError{Err: "csr contains no data"} + } + csr, err := x509.ParseCertificateRequest(pemBlock.Bytes) + if err != nil { + return nil, errutil.UserError{Err: fmt.Sprintf("certificate request could not be parsed: %v", err)} + } + + switch data.role.KeyType { + case "rsa": + // Verify that the key matches the role type + if csr.PublicKeyAlgorithm != x509.RSA { + return nil, errutil.UserError{Err: fmt.Sprintf( + "role requires keys of type %s", + data.role.KeyType)} + } + pubKey, ok := csr.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, errutil.UserError{Err: "could not parse CSR's public key"} + } + + // Verify that the key is at least 2048 bits + if pubKey.N.BitLen() < 2048 { + return nil, errutil.UserError{Err: "RSA keys < 2048 bits are unsafe and not supported"} + } + + // Verify that the bit size is at least the size specified in the role + if pubKey.N.BitLen() < data.role.KeyBits { + return nil, errutil.UserError{Err: fmt.Sprintf( + "role requires a minimum of a %d-bit key, but CSR's key is %d bits", + data.role.KeyBits, + pubKey.N.BitLen())} + } + + case "ec": + // Verify that the key matches the role type + if csr.PublicKeyAlgorithm != x509.ECDSA { + return nil, errutil.UserError{Err: fmt.Sprintf( + "role requires keys of type %s", + data.role.KeyType)} + } + pubKey, ok := csr.PublicKey.(*ecdsa.PublicKey) + if !ok { + return nil, errutil.UserError{Err: "could not parse CSR's public key"} + } + + // Verify that the bit size is at least the size specified in the role + if pubKey.Params().BitSize < data.role.KeyBits { + return nil, errutil.UserError{Err: fmt.Sprintf( + "role requires a minimum of a %d-bit key, but CSR's key is %d bits", + data.role.KeyBits, + pubKey.Params().BitSize)} + } + + case "any": + // We only care about running RSA < 2048 bit checks, so if not RSA + // break out + if csr.PublicKeyAlgorithm != x509.RSA { + break + } + + // Run RSA < 2048 bit checks + pubKey, ok := csr.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, errutil.UserError{Err: "could not parse CSR's public key"} + } + if pubKey.N.BitLen() < 2048 { + return nil, errutil.UserError{Err: "RSA keys < 2048 bits are unsafe and not supported"} + } + + } + + data.csr = csr + + err = generateCreationBundle(b, data) + if err != nil { + return nil, err + } + if data.params == nil { + return nil, errutil.InternalError{Err: "nil parameters received from parameter bundle generation"} + } + + data.params.IsCA = isCA + data.params.UseCSRValues = useCSRValues + + if isCA { + data.params.PermittedDNSDomains = data.apiData.Get("permitted_dns_domains").([]string) + } + + parsedBundle, err := signCertificate(data) + if err != nil { + return nil, err + } + + return parsedBundle, nil +} + +// generateCreationBundle is a shared function that reads parameters supplied +// from the various endpoints and generates a creationParameters with the +// parameters that can be used to issue or sign +func generateCreationBundle(b *backend, data *dataBundle) error { + // Read in names -- CN, DNS and email addresses + var cn string + var ridSerialNumber string + dnsNames := []string{} + emailAddresses := []string{} + { + if data.csr != nil && data.role.UseCSRCommonName { + cn = data.csr.Subject.CommonName + } + if cn == "" { + cn = data.apiData.Get("common_name").(string) + if cn == "" && data.role.RequireCN { + return errutil.UserError{Err: `the common_name field is required, or must be provided in a CSR with "use_csr_common_name" set to true, unless "require_cn" is set to false`} + } + } + + ridSerialNumber = data.apiData.Get("serial_number").(string) + + // only take serial number from CSR if one was not supplied via API + if ridSerialNumber == "" && data.csr != nil { + ridSerialNumber = data.csr.Subject.SerialNumber + } + + if data.csr != nil && data.role.UseCSRSANs { + dnsNames = data.csr.DNSNames + emailAddresses = data.csr.EmailAddresses + } + + if cn != "" && !data.apiData.Get("exclude_cn_from_sans").(bool) { + if strings.Contains(cn, "@") { + // Note: emails are not disallowed if the role's email protection + // flag is false, because they may well be included for + // informational purposes; it is up to the verifying party to + // ensure that email addresses in a subject alternate name can be + // used for the purpose for which they are presented + emailAddresses = append(emailAddresses, cn) + } else { + // Only add to dnsNames if it's actually a DNS name but convert + // idn first + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToASCII(cn) + if err != nil { + return errutil.UserError{Err: err.Error()} + } + if hostnameRegex.MatchString(converted) { + dnsNames = append(dnsNames, converted) + } + } + } + + if data.csr == nil || !data.role.UseCSRSANs { + cnAltRaw, ok := data.apiData.GetOk("alt_names") + if ok { + cnAlt := strutil.ParseDedupLowercaseAndSortStrings(cnAltRaw.(string), ",") + for _, v := range cnAlt { + if strings.Contains(v, "@") { + emailAddresses = append(emailAddresses, v) + } else { + // Only add to dnsNames if it's actually a DNS name but + // convert idn first + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToASCII(v) + if err != nil { + return errutil.UserError{Err: err.Error()} + } + if hostnameRegex.MatchString(converted) { + dnsNames = append(dnsNames, converted) + } + } + } + } + } + + // Check the CN. This ensures that the CN is checked even if it's + // excluded from SANs. + if cn != "" { + badName := validateNames(data, []string{cn}) + if len(badName) != 0 { + return errutil.UserError{Err: fmt.Sprintf( + "common name %s not allowed by this role", badName)} + } + } + + if ridSerialNumber != "" { + badName := validateSerialNumber(data, ridSerialNumber) + if len(badName) != 0 { + return errutil.UserError{Err: fmt.Sprintf( + "serial_number %s not allowed by this role", badName)} + } + } + + // Check for bad email and/or DNS names + badName := validateNames(data, dnsNames) + if len(badName) != 0 { + return errutil.UserError{Err: fmt.Sprintf( + "subject alternate name %s not allowed by this role", badName)} + } + + badName = validateNames(data, emailAddresses) + if len(badName) != 0 { + return errutil.UserError{Err: fmt.Sprintf( + "email address %s not allowed by this role", badName)} + } + } + + var otherSANs map[string][]string + if sans := data.apiData.Get("other_sans").([]string); len(sans) > 0 { + requested, err := parseOtherSANs(sans) + if err != nil { + return errutil.UserError{Err: errwrap.Wrapf("could not parse requested other SAN: {{err}}", err).Error()} + } + badOID, badName, err := validateOtherSANs(data, requested) + switch { + case err != nil: + return errutil.UserError{Err: err.Error()} + case len(badName) > 0: + return errutil.UserError{Err: fmt.Sprintf( + "other SAN %s not allowed for OID %s by this role", badName, badOID)} + case len(badOID) > 0: + return errutil.UserError{Err: fmt.Sprintf( + "other SAN OID %s not allowed by this role", badOID)} + default: + otherSANs = requested + } + } + + // Get and verify any IP SANs + ipAddresses := []net.IP{} + { + if data.csr != nil && data.role.UseCSRSANs { + if len(data.csr.IPAddresses) > 0 { + if !data.role.AllowIPSANs { + return errutil.UserError{Err: fmt.Sprintf( + "IP Subject Alternative Names are not allowed in this role, but was provided some via CSR")} + } + ipAddresses = data.csr.IPAddresses + } + } else { + ipAlt := data.apiData.Get("ip_sans").([]string) + if len(ipAlt) > 0 { + if !data.role.AllowIPSANs { + return errutil.UserError{Err: fmt.Sprintf( + "IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)} + } + for _, v := range ipAlt { + parsedIP := net.ParseIP(v) + if parsedIP == nil { + return errutil.UserError{Err: fmt.Sprintf( + "the value '%s' is not a valid IP address", v)} + } + ipAddresses = append(ipAddresses, parsedIP) + } + } + } + } + + URIs := []*url.URL{} + { + if data.csr != nil && data.role.UseCSRSANs { + if len(data.csr.URIs) > 0 { + if len(data.role.AllowedURISANs) == 0 { + return errutil.UserError{Err: fmt.Sprintf( + "URI Subject Alternative Names are not allowed in this role, but were provided via CSR"), + } + } + + // validate uri sans + for _, uri := range data.csr.URIs { + valid := false + for _, allowed := range data.role.AllowedURISANs { + validURI := glob.Glob(allowed, uri.String()) + if validURI { + valid = true + break + } + } + + if !valid { + return errutil.UserError{Err: fmt.Sprintf( + "URI Subject Alternative Names were provided via CSR which are not valid for this role"), + } + } + + URIs = append(URIs, uri) + } + } + } else { + uriAlt := data.apiData.Get("uri_sans").([]string) + if len(uriAlt) > 0 { + if len(data.role.AllowedURISANs) == 0 { + return errutil.UserError{Err: fmt.Sprintf( + "URI Subject Alternative Names are not allowed in this role, but were provided via the API"), + } + } + + for _, uri := range uriAlt { + valid := false + for _, allowed := range data.role.AllowedURISANs { + validURI := glob.Glob(allowed, uri) + if validURI { + valid = true + break + } + } + + if !valid { + return errutil.UserError{Err: fmt.Sprintf( + "URI Subject Alternative Names were provided via CSR which are not valid for this role"), + } + } + + parsedURI, err := url.Parse(uri) + if parsedURI == nil || err != nil { + return errutil.UserError{Err: fmt.Sprintf( + "the provided URI Subject Alternative Name '%s' is not a valid URI", uri), + } + } + + URIs = append(URIs, parsedURI) + } + } + } + } + + subject := pkix.Name{ + CommonName: cn, + SerialNumber: ridSerialNumber, + Country: strutil.RemoveDuplicates(data.role.Country, false), + Organization: strutil.RemoveDuplicates(data.role.Organization, false), + OrganizationalUnit: strutil.RemoveDuplicates(data.role.OU, false), + Locality: strutil.RemoveDuplicates(data.role.Locality, false), + Province: strutil.RemoveDuplicates(data.role.Province, false), + StreetAddress: strutil.RemoveDuplicates(data.role.StreetAddress, false), + PostalCode: strutil.RemoveDuplicates(data.role.PostalCode, false), + } + + // Get the TTL and verify it against the max allowed + var ttl time.Duration + var maxTTL time.Duration + var notAfter time.Time + { + ttl = time.Duration(data.apiData.Get("ttl").(int)) * time.Second + + if ttl == 0 && data.role.TTL > 0 { + ttl = data.role.TTL + } + + if data.role.MaxTTL > 0 { + maxTTL = data.role.MaxTTL + } + + if ttl == 0 { + ttl = b.System().DefaultLeaseTTL() + } + if maxTTL == 0 { + maxTTL = b.System().MaxLeaseTTL() + } + if ttl > maxTTL { + ttl = maxTTL + } + + notAfter = time.Now().Add(ttl) + + // If it's not self-signed, verify that the issued certificate won't be + // valid past the lifetime of the CA certificate + if data.signingBundle != nil && + notAfter.After(data.signingBundle.Certificate.NotAfter) && !data.role.AllowExpirationPastCA { + + return errutil.UserError{Err: fmt.Sprintf( + "cannot satisfy request, as TTL would result in notAfter %s that is beyond the expiration of the CA certificate at %s", notAfter.Format(time.RFC3339Nano), data.signingBundle.Certificate.NotAfter.Format(time.RFC3339Nano))} + } + } + + data.params = &creationParameters{ + Subject: subject, + DNSNames: dnsNames, + EmailAddresses: emailAddresses, + IPAddresses: ipAddresses, + URIs: URIs, + OtherSANs: otherSANs, + KeyType: data.role.KeyType, + KeyBits: data.role.KeyBits, + NotAfter: notAfter, + KeyUsage: x509.KeyUsage(parseKeyUsages(data.role.KeyUsage)), + ExtKeyUsage: parseExtKeyUsages(data.role), + ExtKeyUsageOIDs: data.role.ExtKeyUsageOIDs, + PolicyIdentifiers: data.role.PolicyIdentifiers, + BasicConstraintsValidForNonCA: data.role.BasicConstraintsValidForNonCA, + } + + // Don't deal with URLs or max path length if it's self-signed, as these + // normally come from the signing bundle + if data.signingBundle == nil { + return nil + } + + // This will have been read in from the getURLs function + data.params.URLs = data.signingBundle.URLs + + // If the max path length in the role is not nil, it was specified at + // generation time with the max_path_length parameter; otherwise derive it + // from the signing certificate + if data.role.MaxPathLength != nil { + data.params.MaxPathLength = *data.role.MaxPathLength + } else { + switch { + case data.signingBundle.Certificate.MaxPathLen < 0: + data.params.MaxPathLength = -1 + case data.signingBundle.Certificate.MaxPathLen == 0 && + data.signingBundle.Certificate.MaxPathLenZero: + // The signing function will ensure that we do not issue a CA cert + data.params.MaxPathLength = 0 + default: + // If this takes it to zero, we handle this case later if + // necessary + data.params.MaxPathLength = data.signingBundle.Certificate.MaxPathLen - 1 + } + } + + return nil +} + +// addKeyUsages adds appropriate key usages to the template given the creation +// information +func addKeyUsages(data *dataBundle, certTemplate *x509.Certificate) { + if data.params.IsCA { + certTemplate.KeyUsage = x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign) + return + } + + certTemplate.KeyUsage = data.params.KeyUsage + + if data.params.ExtKeyUsage&anyExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageAny) + } + + if data.params.ExtKeyUsage&serverAuthExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) + } + + if data.params.ExtKeyUsage&clientAuthExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageClientAuth) + } + + if data.params.ExtKeyUsage&codeSigningExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageCodeSigning) + } + + if data.params.ExtKeyUsage&emailProtectionExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageEmailProtection) + } + + if data.params.ExtKeyUsage&ipsecEndSystemExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageIPSECEndSystem) + } + + if data.params.ExtKeyUsage&ipsecTunnelExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageIPSECTunnel) + } + + if data.params.ExtKeyUsage&ipsecUserExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageIPSECUser) + } + + if data.params.ExtKeyUsage&timeStampingExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageTimeStamping) + } + + if data.params.ExtKeyUsage&ocspSigningExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageOCSPSigning) + } + + if data.params.ExtKeyUsageµsoftServerGatedCryptoExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageMicrosoftServerGatedCrypto) + } + + if data.params.ExtKeyUsage&netscapeServerGatedCryptoExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageNetscapeServerGatedCrypto) + } + + if data.params.ExtKeyUsageµsoftCommercialCodeSigningExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageMicrosoftCommercialCodeSigning) + } + + if data.params.ExtKeyUsageµsoftKernelCodeSigningExtKeyUsage != 0 { + certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageMicrosoftKernelCodeSigning) + } +} + +// addPolicyIdentifiers adds certificate policies extension +// +func addPolicyIdentifiers(data *dataBundle, certTemplate *x509.Certificate) { + for _, oidstr := range data.params.PolicyIdentifiers { + oid, err := stringToOid(oidstr) + if err == nil { + certTemplate.PolicyIdentifiers = append(certTemplate.PolicyIdentifiers, oid) + } + } +} + +// addExtKeyUsageOids adds custom extended key usage OIDs to certificate +func addExtKeyUsageOids(data *dataBundle, certTemplate *x509.Certificate) { + for _, oidstr := range data.params.ExtKeyUsageOIDs { + oid, err := stringToOid(oidstr) + if err == nil { + certTemplate.UnknownExtKeyUsage = append(certTemplate.UnknownExtKeyUsage, oid) + } + } +} + +// Performs the heavy lifting of creating a certificate. Returns +// a fully-filled-in ParsedCertBundle. +func createCertificate(data *dataBundle) (*certutil.ParsedCertBundle, error) { + var err error + result := &certutil.ParsedCertBundle{} + + serialNumber, err := certutil.GenerateSerialNumber() + if err != nil { + return nil, err + } + + if err := certutil.GeneratePrivateKey(data.params.KeyType, + data.params.KeyBits, + result); err != nil { + return nil, err + } + + subjKeyID, err := certutil.GetSubjKeyID(result.PrivateKey) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error getting subject key ID: %s", err)} + } + + certTemplate := &x509.Certificate{ + SerialNumber: serialNumber, + NotBefore: time.Now().Add(-30 * time.Second), + NotAfter: data.params.NotAfter, + IsCA: false, + SubjectKeyId: subjKeyID, + Subject: data.params.Subject, + DNSNames: data.params.DNSNames, + EmailAddresses: data.params.EmailAddresses, + IPAddresses: data.params.IPAddresses, + URIs: data.params.URIs, + } + + if err := handleOtherSANs(certTemplate, data.params.OtherSANs); err != nil { + return nil, errutil.InternalError{Err: errwrap.Wrapf("error marshaling other SANs: {{err}}", err).Error()} + } + + // Add this before calling addKeyUsages + if data.signingBundle == nil { + certTemplate.IsCA = true + } else if data.params.BasicConstraintsValidForNonCA { + certTemplate.BasicConstraintsValid = true + certTemplate.IsCA = false + } + + // This will only be filled in from the generation paths + if len(data.params.PermittedDNSDomains) > 0 { + certTemplate.PermittedDNSDomains = data.params.PermittedDNSDomains + certTemplate.PermittedDNSDomainsCritical = true + } + + addPolicyIdentifiers(data, certTemplate) + + addKeyUsages(data, certTemplate) + + addExtKeyUsageOids(data, certTemplate) + + certTemplate.IssuingCertificateURL = data.params.URLs.IssuingCertificates + certTemplate.CRLDistributionPoints = data.params.URLs.CRLDistributionPoints + certTemplate.OCSPServer = data.params.URLs.OCSPServers + + var certBytes []byte + if data.signingBundle != nil { + switch data.signingBundle.PrivateKeyType { + case certutil.RSAPrivateKey: + certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case certutil.ECPrivateKey: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + } + + caCert := data.signingBundle.Certificate + certTemplate.AuthorityKeyId = caCert.SubjectKeyId + + err = checkPermittedDNSDomains(certTemplate, caCert) + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + + certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, result.PrivateKey.Public(), data.signingBundle.PrivateKey) + } else { + // Creating a self-signed root + if data.params.MaxPathLength == 0 { + certTemplate.MaxPathLen = 0 + certTemplate.MaxPathLenZero = true + } else { + certTemplate.MaxPathLen = data.params.MaxPathLength + } + + switch data.params.KeyType { + case "rsa": + certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case "ec": + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + } + + certTemplate.AuthorityKeyId = subjKeyID + certTemplate.BasicConstraintsValid = true + certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, result.PrivateKey.Public(), result.PrivateKey) + } + + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} + } + + result.CertificateBytes = certBytes + result.Certificate, err = x509.ParseCertificate(certBytes) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to parse created certificate: %s", err)} + } + + if data.signingBundle != nil { + if len(data.signingBundle.Certificate.AuthorityKeyId) > 0 && + !bytes.Equal(data.signingBundle.Certificate.AuthorityKeyId, data.signingBundle.Certificate.SubjectKeyId) { + + result.CAChain = []*certutil.CertBlock{ + &certutil.CertBlock{ + Certificate: data.signingBundle.Certificate, + Bytes: data.signingBundle.CertificateBytes, + }, + } + result.CAChain = append(result.CAChain, data.signingBundle.CAChain...) + } + } + + return result, nil +} + +// Creates a CSR. This is currently only meant for use when +// generating an intermediate certificate. +func createCSR(data *dataBundle) (*certutil.ParsedCSRBundle, error) { + var err error + result := &certutil.ParsedCSRBundle{} + + if err := certutil.GeneratePrivateKey(data.params.KeyType, + data.params.KeyBits, + result); err != nil { + return nil, err + } + + // Like many root CAs, other information is ignored + csrTemplate := &x509.CertificateRequest{ + Subject: data.params.Subject, + DNSNames: data.params.DNSNames, + EmailAddresses: data.params.EmailAddresses, + IPAddresses: data.params.IPAddresses, + URIs: data.params.URIs, + } + + if err := handleOtherCSRSANs(csrTemplate, data.params.OtherSANs); err != nil { + return nil, errutil.InternalError{Err: errwrap.Wrapf("error marshaling other SANs: {{err}}", err).Error()} + } + + if data.apiData != nil && data.apiData.Get("add_basic_constraints").(bool) { + type basicConstraints struct { + IsCA bool `asn1:"optional"` + MaxPathLen int `asn1:"optional,default:-1"` + } + val, err := asn1.Marshal(basicConstraints{IsCA: true, MaxPathLen: -1}) + if err != nil { + return nil, errutil.InternalError{Err: errwrap.Wrapf("error marshaling basic constraints: {{err}}", err).Error()} + } + ext := pkix.Extension{ + Id: oidExtensionBasicConstraints, + Value: val, + Critical: true, + } + csrTemplate.ExtraExtensions = append(csrTemplate.ExtraExtensions, ext) + } + + switch data.params.KeyType { + case "rsa": + csrTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case "ec": + csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + } + + csr, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, result.PrivateKey) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} + } + + result.CSRBytes = csr + result.CSR, err = x509.ParseCertificateRequest(csr) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to parse created certificate: %v", err)} + } + + return result, nil +} + +// Performs the heavy lifting of generating a certificate from a CSR. +// Returns a ParsedCertBundle sans private keys. +func signCertificate(data *dataBundle) (*certutil.ParsedCertBundle, error) { + switch { + case data == nil: + return nil, errutil.UserError{Err: "nil data bundle given to signCertificate"} + case data.params == nil: + return nil, errutil.UserError{Err: "nil parameters given to signCertificate"} + case data.signingBundle == nil: + return nil, errutil.UserError{Err: "nil signing bundle given to signCertificate"} + case data.csr == nil: + return nil, errutil.UserError{Err: "nil csr given to signCertificate"} + } + + err := data.csr.CheckSignature() + if err != nil { + return nil, errutil.UserError{Err: "request signature invalid"} + } + + result := &certutil.ParsedCertBundle{} + + serialNumber, err := certutil.GenerateSerialNumber() + if err != nil { + return nil, err + } + + marshaledKey, err := x509.MarshalPKIXPublicKey(data.csr.PublicKey) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("error marshalling public key: %s", err)} + } + subjKeyID := sha1.Sum(marshaledKey) + + caCert := data.signingBundle.Certificate + + certTemplate := &x509.Certificate{ + SerialNumber: serialNumber, + Subject: data.params.Subject, + NotBefore: time.Now().Add(-30 * time.Second), + NotAfter: data.params.NotAfter, + SubjectKeyId: subjKeyID[:], + AuthorityKeyId: caCert.SubjectKeyId, + } + + switch data.signingBundle.PrivateKeyType { + case certutil.RSAPrivateKey: + certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case certutil.ECPrivateKey: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + } + + if data.params.UseCSRValues { + certTemplate.Subject = data.csr.Subject + + certTemplate.DNSNames = data.csr.DNSNames + certTemplate.EmailAddresses = data.csr.EmailAddresses + certTemplate.IPAddresses = data.csr.IPAddresses + certTemplate.URIs = data.csr.URIs + + for _, name := range data.csr.Extensions { + if !name.Id.Equal(oidExtensionBasicConstraints) { + certTemplate.ExtraExtensions = append(certTemplate.ExtraExtensions, name) + } + } + + } else { + certTemplate.DNSNames = data.params.DNSNames + certTemplate.EmailAddresses = data.params.EmailAddresses + certTemplate.IPAddresses = data.params.IPAddresses + certTemplate.URIs = data.csr.URIs + } + + if err := handleOtherSANs(certTemplate, data.params.OtherSANs); err != nil { + return nil, errutil.InternalError{Err: errwrap.Wrapf("error marshaling other SANs: {{err}}", err).Error()} + } + + addPolicyIdentifiers(data, certTemplate) + + addKeyUsages(data, certTemplate) + + addExtKeyUsageOids(data, certTemplate) + + var certBytes []byte + + certTemplate.IssuingCertificateURL = data.params.URLs.IssuingCertificates + certTemplate.CRLDistributionPoints = data.params.URLs.CRLDistributionPoints + certTemplate.OCSPServer = data.signingBundle.URLs.OCSPServers + + if data.params.IsCA { + certTemplate.BasicConstraintsValid = true + certTemplate.IsCA = true + + if data.signingBundle.Certificate.MaxPathLen == 0 && + data.signingBundle.Certificate.MaxPathLenZero { + return nil, errutil.UserError{Err: "signing certificate has a max path length of zero, and cannot issue further CA certificates"} + } + + certTemplate.MaxPathLen = data.params.MaxPathLength + if certTemplate.MaxPathLen == 0 { + certTemplate.MaxPathLenZero = true + } + } else if data.params.BasicConstraintsValidForNonCA { + certTemplate.BasicConstraintsValid = true + certTemplate.IsCA = false + } + + if len(data.params.PermittedDNSDomains) > 0 { + certTemplate.PermittedDNSDomains = data.params.PermittedDNSDomains + certTemplate.PermittedDNSDomainsCritical = true + } + err = checkPermittedDNSDomains(certTemplate, caCert) + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + + certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, data.csr.PublicKey, data.signingBundle.PrivateKey) + + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} + } + + result.CertificateBytes = certBytes + result.Certificate, err = x509.ParseCertificate(certBytes) + if err != nil { + return nil, errutil.InternalError{Err: fmt.Sprintf("unable to parse created certificate: %s", err)} + } + + result.CAChain = data.signingBundle.GetCAChain() + + return result, nil +} + +func checkPermittedDNSDomains(template, ca *x509.Certificate) error { + if len(ca.PermittedDNSDomains) == 0 { + return nil + } + + namesToCheck := map[string]struct{}{ + template.Subject.CommonName: struct{}{}, + } + for _, name := range template.DNSNames { + namesToCheck[name] = struct{}{} + } + + var badName string +NameCheck: + for name := range namesToCheck { + for _, perm := range ca.PermittedDNSDomains { + switch { + case strings.HasPrefix(perm, ".") && strings.HasSuffix(name, perm): + // .example.com matches my.host.example.com and + // host.example.com but does not match example.com + break NameCheck + case perm == name: + break NameCheck + } + } + badName = name + break + } + + if badName == "" { + return nil + } + + return fmt.Errorf("name %q disallowed by CA's permitted DNS domains", badName) +} + +func convertRespToPKCS8(resp *logical.Response) error { + privRaw, ok := resp.Data["private_key"] + if !ok { + return nil + } + priv, ok := privRaw.(string) + if !ok { + return fmt.Errorf("error converting response to pkcs8: could not parse original value as string") + } + + privKeyTypeRaw, ok := resp.Data["private_key_type"] + if !ok { + return fmt.Errorf("error converting response to pkcs8: %q not found in response", "private_key_type") + } + privKeyType, ok := privKeyTypeRaw.(certutil.PrivateKeyType) + if !ok { + return fmt.Errorf("error converting response to pkcs8: could not parse original type value as string") + } + + var keyData []byte + var pemUsed bool + var err error + var signer crypto.Signer + + block, _ := pem.Decode([]byte(priv)) + if block == nil { + keyData, err = base64.StdEncoding.DecodeString(priv) + if err != nil { + return errwrap.Wrapf("error converting response to pkcs8: error decoding original value: {{err}}", err) + } + } else { + keyData = block.Bytes + pemUsed = true + } + + switch privKeyType { + case certutil.RSAPrivateKey: + signer, err = x509.ParsePKCS1PrivateKey(keyData) + case certutil.ECPrivateKey: + signer, err = x509.ParseECPrivateKey(keyData) + default: + return fmt.Errorf("unknown private key type %q", privKeyType) + } + if err != nil { + return errwrap.Wrapf("error converting response to pkcs8: error parsing previous key: {{err}}", err) + } + + keyData, err = x509.MarshalPKCS8PrivateKey(signer) + if err != nil { + return errwrap.Wrapf("error converting response to pkcs8: error marshaling pkcs8 key: {{err}}", err) + } + + if pemUsed { + block.Type = "PRIVATE KEY" + block.Bytes = keyData + resp.Data["private_key"] = strings.TrimSpace(string(pem.EncodeToMemory(block))) + } else { + resp.Data["private_key"] = base64.StdEncoding.EncodeToString(keyData) + } + + return nil +} + +func handleOtherCSRSANs(in *x509.CertificateRequest, sans map[string][]string) error { + certTemplate := &x509.Certificate{ + DNSNames: in.DNSNames, + IPAddresses: in.IPAddresses, + EmailAddresses: in.EmailAddresses, + URIs: in.URIs, + } + if err := handleOtherSANs(certTemplate, sans); err != nil { + return err + } + if len(certTemplate.ExtraExtensions) > 0 { + for _, v := range certTemplate.ExtraExtensions { + in.ExtraExtensions = append(in.ExtraExtensions, v) + } + } + return nil +} + +func handleOtherSANs(in *x509.Certificate, sans map[string][]string) error { + // If other SANs is empty we return which causes normal Go stdlib parsing + // of the other SAN types + if len(sans) == 0 { + return nil + } + + var rawValues []asn1.RawValue + + // We need to generate an IMPLICIT sequence for compatibility with OpenSSL + // -- it's an open question what the default for RFC 5280 actually is, see + // https://github.com/openssl/openssl/issues/5091 -- so we have to use + // cryptobyte because using the asn1 package's marshaling always produces + // an EXPLICIT sequence. Note that asn1 is way too magical according to + // agl, and cryptobyte is modeled after the CBB/CBS bits that agl put into + // boringssl. + for oid, vals := range sans { + for _, val := range vals { + var b cryptobyte.Builder + oidStr, err := stringToOid(oid) + if err != nil { + return err + } + b.AddASN1ObjectIdentifier(oidStr) + b.AddASN1(cbbasn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { + b.AddASN1(cbbasn1.UTF8String, func(b *cryptobyte.Builder) { + b.AddBytes([]byte(val)) + }) + }) + m, err := b.Bytes() + if err != nil { + return err + } + rawValues = append(rawValues, asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: m}) + } + } + + // If other SANs is empty we return which causes normal Go stdlib parsing + // of the other SAN types + if len(rawValues) == 0 { + return nil + } + + // Append any existing SANs, sans marshalling + rawValues = append(rawValues, marshalSANs(in.DNSNames, in.EmailAddresses, in.IPAddresses, in.URIs)...) + + // Marshal and add to ExtraExtensions + ext := pkix.Extension{ + // This is the defined OID for subjectAltName + Id: asn1.ObjectIdentifier{2, 5, 29, 17}, + } + var err error + ext.Value, err = asn1.Marshal(rawValues) + if err != nil { + return err + } + in.ExtraExtensions = append(in.ExtraExtensions, ext) + + return nil +} + +// Note: Taken from the Go source code since it's not public, and used in the +// modified function below (which also uses these consts upstream) +const ( + nameTypeEmail = 1 + nameTypeDNS = 2 + nameTypeURI = 6 + nameTypeIP = 7 +) + +// Note: Taken from the Go source code since it's not public, plus changed to not marshal +// marshalSANs marshals a list of addresses into a the contents of an X.509 +// SubjectAlternativeName extension. +func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) []asn1.RawValue { + var rawValues []asn1.RawValue + for _, name := range dnsNames { + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)}) + } + for _, email := range emailAddresses { + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)}) + } + for _, rawIP := range ipAddresses { + // If possible, we always want to encode IPv4 addresses in 4 bytes. + ip := rawIP.To4() + if ip == nil { + ip = rawIP + } + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip}) + } + for _, uri := range uris { + rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())}) + } + return rawValues +} + +func stringToOid(in string) (asn1.ObjectIdentifier, error) { + split := strings.Split(in, ".") + ret := make(asn1.ObjectIdentifier, 0, len(split)) + for _, v := range split { + i, err := strconv.Atoi(v) + if err != nil { + return nil, err + } + ret = append(ret, i) + } + return asn1.ObjectIdentifier(ret), nil +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/crl_util.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/crl_util.go new file mode 100644 index 000000000..8eb65ed58 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/crl_util.go @@ -0,0 +1,205 @@ +package pki + +import ( + "context" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "fmt" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" +) + +type revocationInfo struct { + CertificateBytes []byte `json:"certificate_bytes"` + RevocationTime int64 `json:"revocation_time"` + RevocationTimeUTC time.Time `json:"revocation_time_utc"` +} + +// Revokes a cert, and tries to be smart about error recovery +func revokeCert(ctx context.Context, b *backend, req *logical.Request, serial string, fromLease bool) (*logical.Response, error) { + // As this backend is self-contained and this function does not hook into + // third parties to manage users or resources, if the mount is tainted, + // revocation doesn't matter anyways -- the CRL that would be written will + // be immediately blown away by the view being cleared. So we can simply + // fast path a successful exit. + if b.System().Tainted() { + return nil, nil + } + + alreadyRevoked := false + var revInfo revocationInfo + + revEntry, err := fetchCertBySerial(ctx, req, "revoked/", serial) + if err != nil { + switch err.(type) { + case errutil.UserError: + return logical.ErrorResponse(err.Error()), nil + case errutil.InternalError: + return nil, err + } + } + if revEntry != nil { + // Set the revocation info to the existing values + alreadyRevoked = true + err = revEntry.DecodeJSON(&revInfo) + if err != nil { + return nil, fmt.Errorf("error decoding existing revocation info") + } + } + + if !alreadyRevoked { + certEntry, err := fetchCertBySerial(ctx, req, "certs/", serial) + if err != nil { + switch err.(type) { + case errutil.UserError: + return logical.ErrorResponse(err.Error()), nil + case errutil.InternalError: + return nil, err + } + } + if certEntry == nil { + return logical.ErrorResponse(fmt.Sprintf("certificate with serial %s not found", serial)), nil + } + + cert, err := x509.ParseCertificate(certEntry.Value) + if err != nil { + return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) + } + if cert == nil { + return nil, fmt.Errorf("got a nil certificate") + } + + if cert.NotAfter.Before(time.Now()) { + return nil, nil + } + + // Compatibility: Don't revoke CAs if they had leases. New CAs going + // forward aren't issued leases. + if cert.IsCA && fromLease { + return nil, nil + } + + currTime := time.Now() + revInfo.CertificateBytes = certEntry.Value + revInfo.RevocationTime = currTime.Unix() + revInfo.RevocationTimeUTC = currTime.UTC() + + revEntry, err = logical.StorageEntryJSON("revoked/"+normalizeSerial(serial), revInfo) + if err != nil { + return nil, fmt.Errorf("error creating revocation entry") + } + + err = req.Storage.Put(ctx, revEntry) + if err != nil { + return nil, fmt.Errorf("error saving revoked certificate to new location") + } + + } + + crlErr := buildCRL(ctx, b, req) + switch crlErr.(type) { + case errutil.UserError: + return logical.ErrorResponse(fmt.Sprintf("Error during CRL building: %s", crlErr)), nil + case errutil.InternalError: + return nil, errwrap.Wrapf("error encountered during CRL building: {{err}}", crlErr) + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "revocation_time": revInfo.RevocationTime, + }, + } + if !revInfo.RevocationTimeUTC.IsZero() { + resp.Data["revocation_time_rfc3339"] = revInfo.RevocationTimeUTC.Format(time.RFC3339Nano) + } + return resp, nil +} + +// Builds a CRL by going through the list of revoked certificates and building +// a new CRL with the stored revocation times and serial numbers. +func buildCRL(ctx context.Context, b *backend, req *logical.Request) error { + revokedSerials, err := req.Storage.List(ctx, "revoked/") + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error fetching list of revoked certs: %s", err)} + } + + revokedCerts := []pkix.RevokedCertificate{} + var revInfo revocationInfo + for _, serial := range revokedSerials { + revokedEntry, err := req.Storage.Get(ctx, "revoked/"+serial) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("unable to fetch revoked cert with serial %s: %s", serial, err)} + } + if revokedEntry == nil { + return errutil.InternalError{Err: fmt.Sprintf("revoked certificate entry for serial %s is nil", serial)} + } + if revokedEntry.Value == nil || len(revokedEntry.Value) == 0 { + // TODO: In this case, remove it and continue? How likely is this to + // happen? Alternately, could skip it entirely, or could implement a + // delete function so that there is a way to remove these + return errutil.InternalError{Err: fmt.Sprintf("found revoked serial but actual certificate is empty")} + } + + err = revokedEntry.DecodeJSON(&revInfo) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error decoding revocation entry for serial %s: %s", serial, err)} + } + + revokedCert, err := x509.ParseCertificate(revInfo.CertificateBytes) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("unable to parse stored revoked certificate with serial %s: %s", serial, err)} + } + + // NOTE: We have to change this to UTC time because the CRL standard + // mandates it but Go will happily encode the CRL without this. + newRevCert := pkix.RevokedCertificate{ + SerialNumber: revokedCert.SerialNumber, + } + if !revInfo.RevocationTimeUTC.IsZero() { + newRevCert.RevocationTime = revInfo.RevocationTimeUTC + } else { + newRevCert.RevocationTime = time.Unix(revInfo.RevocationTime, 0).UTC() + } + revokedCerts = append(revokedCerts, newRevCert) + } + + signingBundle, caErr := fetchCAInfo(ctx, req) + switch caErr.(type) { + case errutil.UserError: + return errutil.UserError{Err: fmt.Sprintf("could not fetch the CA certificate: %s", caErr)} + case errutil.InternalError: + return errutil.InternalError{Err: fmt.Sprintf("error fetching CA certificate: %s", caErr)} + } + + crlLifetime := b.crlLifetime + crlInfo, err := b.CRL(ctx, req.Storage) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error fetching CRL config information: %s", err)} + } + if crlInfo != nil { + crlDur, err := time.ParseDuration(crlInfo.Expiry) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error parsing CRL duration of %s", crlInfo.Expiry)} + } + crlLifetime = crlDur + } + + crlBytes, err := signingBundle.Certificate.CreateCRL(rand.Reader, signingBundle.PrivateKey, revokedCerts, time.Now(), time.Now().Add(crlLifetime)) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error creating new CRL: %s", err)} + } + + err = req.Storage.Put(ctx, &logical.StorageEntry{ + Key: "crl", + Value: crlBytes, + }) + if err != nil { + return errutil.InternalError{Err: fmt.Sprintf("error storing CRL: %s", err)} + } + + return nil +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/fields.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/fields.go new file mode 100644 index 000000000..dee7779be --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/fields.go @@ -0,0 +1,232 @@ +package pki + +import "github.com/hashicorp/vault/logical/framework" + +// addIssueAndSignCommonFields adds fields common to both CA and non-CA issuing +// and signing +func addIssueAndSignCommonFields(fields map[string]*framework.FieldSchema) map[string]*framework.FieldSchema { + fields["exclude_cn_from_sans"] = &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: `If true, the Common Name will not be +included in DNS or Email Subject Alternate Names. +Defaults to false (CN is included).`, + } + + fields["format"] = &framework.FieldSchema{ + Type: framework.TypeString, + Default: "pem", + Description: `Format for returned data. Can be "pem", "der", +or "pem_bundle". If "pem_bundle" any private +key and issuing cert will be appended to the +certificate pem. Defaults to "pem".`, + } + + fields["private_key_format"] = &framework.FieldSchema{ + Type: framework.TypeString, + Default: "der", + Description: `Format for the returned private key. +Generally the default will be controlled by the "format" +parameter as either base64-encoded DER or PEM-encoded DER. +However, this can be set to "pkcs8" to have the returned +private key contain base64-encoded pkcs8 or PEM-encoded +pkcs8 instead. Defaults to "der".`, + } + + fields["ip_sans"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `The requested IP SANs, if any, in a +comma-delimited list`, + } + + fields["uri_sans"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `The requested URI SANs, if any, in a +comma-delimited list.`, + } + + fields["other_sans"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Requested other SANs, in an array with the format +;UTF8: for each entry.`, + } + + return fields +} + +// addNonCACommonFields adds fields with help text specific to non-CA +// certificate issuing and signing +func addNonCACommonFields(fields map[string]*framework.FieldSchema) map[string]*framework.FieldSchema { + fields = addIssueAndSignCommonFields(fields) + + fields["role"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The desired role with configuration for this +request`, + } + + fields["common_name"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The requested common name; if you want more than +one, specify the alternative names in the +alt_names map. If email protection is enabled +in the role, this may be an email address.`, + } + + fields["alt_names"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The requested Subject Alternative Names, if any, +in a comma-delimited list. If email protection +is enabled for the role, this may contain +email addresses.`, + } + + fields["serial_number"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The requested serial number, if any. If you want +more than one, specify alternative names in +the alt_names map using OID 2.5.4.5.`, + } + + fields["ttl"] = &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: `The requested Time To Live for the certificate; +sets the expiration date. If not specified +the role default, backend default, or system +default TTL is used, in that order. Cannot +be larger than the role max TTL.`, + } + + return fields +} + +// addCACommonFields adds fields with help text specific to CA +// certificate issuing and signing +func addCACommonFields(fields map[string]*framework.FieldSchema) map[string]*framework.FieldSchema { + fields = addIssueAndSignCommonFields(fields) + + fields["alt_names"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The requested Subject Alternative Names, if any, +in a comma-delimited list. May contain both +DNS names and email addresses.`, + } + + fields["common_name"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The requested common name; if you want more than +one, specify the alternative names in the alt_names +map. If not specified when signing, the common +name will be taken from the CSR; other names +must still be specified in alt_names or ip_sans.`, + } + + fields["ttl"] = &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: `The requested Time To Live for the certificate; +sets the expiration date. If not specified +the role default, backend default, or system +default TTL is used, in that order. Cannot +be larger than the mount max TTL. Note: +this only has an effect when generating +a CA cert or signing a CA cert, not when +generating a CSR for an intermediate CA.`, + } + + fields["ou"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, OU (OrganizationalUnit) will be set to +this value.`, + } + + fields["organization"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, O (Organization) will be set to +this value.`, + } + + fields["country"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Country will be set to +this value.`, + } + + fields["locality"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Locality will be set to +this value.`, + } + + fields["province"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Province will be set to +this value.`, + } + + fields["street_address"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Street Address will be set to +this value.`, + } + + fields["postal_code"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Postal Code will be set to +this value.`, + } + + fields["serial_number"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The requested serial number, if any. If you want +more than one, specify alternative names in +the alt_names map using OID 2.5.4.5.`, + } + + return fields +} + +// addCAKeyGenerationFields adds fields with help text specific to CA key +// generation and exporting +func addCAKeyGenerationFields(fields map[string]*framework.FieldSchema) map[string]*framework.FieldSchema { + fields["exported"] = &framework.FieldSchema{ + Type: framework.TypeString, + Description: `Must be "internal" or "exported". If set to +"exported", the generated private key will be +returned. This is your *only* chance to retrieve +the private key!`, + } + + fields["key_bits"] = &framework.FieldSchema{ + Type: framework.TypeInt, + Default: 2048, + Description: `The number of bits to use. You will almost +certainly want to change this if you adjust +the key_type.`, + } + + fields["key_type"] = &framework.FieldSchema{ + Type: framework.TypeString, + Default: "rsa", + Description: `The type of key to use; defaults to RSA. "rsa" +and "ec" are the only valid values.`, + } + + return fields +} + +// addCAIssueFields adds fields common to CA issuing, e.g. when returning +// an actual certificate +func addCAIssueFields(fields map[string]*framework.FieldSchema) map[string]*framework.FieldSchema { + fields["max_path_length"] = &framework.FieldSchema{ + Type: framework.TypeInt, + Default: -1, + Description: "The maximum allowable path length", + } + + fields["permitted_dns_domains"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Domains for which this certificate is allowed to sign or issue child certificates. If set, all DNS names (subject and alt) on child certs must be exact matches or subsets of the given domains (see https://tools.ietf.org/html/rfc5280#section-4.2.1.10).`, + } + + return fields +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_ca.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_ca.go new file mode 100644 index 000000000..f21e3665c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_ca.go @@ -0,0 +1,135 @@ +package pki + +import ( + "context" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/certutil" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathConfigCA(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "config/ca", + Fields: map[string]*framework.FieldSchema{ + "pem_bundle": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `PEM-format, concatenated unencrypted +secret key and certificate.`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathCAWrite, + }, + + HelpSynopsis: pathConfigCAHelpSyn, + HelpDescription: pathConfigCAHelpDesc, + } +} + +func (b *backend) pathCAWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + pemBundle := data.Get("pem_bundle").(string) + + if pemBundle == "" { + return logical.ErrorResponse("'pem_bundle' was empty"), nil + } + + parsedBundle, err := certutil.ParsePEMBundle(pemBundle) + if err != nil { + switch err.(type) { + case errutil.InternalError: + return nil, err + default: + return logical.ErrorResponse(err.Error()), nil + } + } + + if parsedBundle.PrivateKey == nil || + parsedBundle.PrivateKeyType == certutil.UnknownPrivateKey { + return logical.ErrorResponse("private key not found in the PEM bundle"), nil + } + + if parsedBundle.Certificate == nil { + return logical.ErrorResponse("no certificate found in the PEM bundle"), nil + } + + if !parsedBundle.Certificate.IsCA { + return logical.ErrorResponse("the given certificate is not marked for CA use and cannot be used with this backend"), nil + } + + cb, err := parsedBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw values into cert bundle: {{err}}", err) + } + + entry, err := logical.StorageEntryJSON("config/ca_bundle", cb) + if err != nil { + return nil, err + } + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + // For ease of later use, also store just the certificate at a known + // location, plus a fresh CRL + entry.Key = "ca" + entry.Value = parsedBundle.CertificateBytes + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + err = buildCRL(ctx, b, req) + + return nil, err +} + +const pathConfigCAHelpSyn = ` +Set the CA certificate and private key used for generated credentials. +` + +const pathConfigCAHelpDesc = ` +This sets the CA information used for credentials generated by this +by this mount. This must be a PEM-format, concatenated unencrypted +secret key and certificate. + +For security reasons, the secret key cannot be retrieved later. +` + +const pathConfigCAGenerateHelpSyn = ` +Generate a new CA certificate and private key used for signing. +` + +const pathConfigCAGenerateHelpDesc = ` +This path generates a CA certificate and private key to be used for +credentials generated by this mount. The path can either +end in "internal" or "exported"; this controls whether the +unencrypted private key is exported after generation. This will +be your only chance to export the private key; for security reasons +it cannot be read or exported later. + +If the "type" option is set to "self-signed", the generated +certificate will be a self-signed root CA. Otherwise, this mount +will act as an intermediate CA; a CSR will be returned, to be signed +by your chosen CA (which could be another mount of this backend). +Note that the CRL path will be set to this mount's CRL path; if you +need further customization it is recommended that you create a CSR +separately and get it signed. Either way, use the "config/ca/set" +endpoint to load the signed certificate into Vault. +` + +const pathConfigCASignHelpSyn = ` +Generate a signed CA certificate from a CSR. +` + +const pathConfigCASignHelpDesc = ` +This path generates a CA certificate to be used for credentials +generated by the certificate's destination mount. + +Use the "config/ca/set" endpoint to load the signed certificate +into Vault another Vault mount. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_crl.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_crl.go new file mode 100644 index 000000000..b9eb88af5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_crl.go @@ -0,0 +1,102 @@ +package pki + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// CRLConfig holds basic CRL configuration information +type crlConfig struct { + Expiry string `json:"expiry" mapstructure:"expiry" structs:"expiry"` +} + +func pathConfigCRL(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "config/crl", + Fields: map[string]*framework.FieldSchema{ + "expiry": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The amount of time the generated CRL should be +valid; defaults to 72 hours`, + Default: "72h", + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathCRLRead, + logical.UpdateOperation: b.pathCRLWrite, + }, + + HelpSynopsis: pathConfigCRLHelpSyn, + HelpDescription: pathConfigCRLHelpDesc, + } +} + +func (b *backend) CRL(ctx context.Context, s logical.Storage) (*crlConfig, error) { + entry, err := s.Get(ctx, "config/crl") + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var result crlConfig + if err := entry.DecodeJSON(&result); err != nil { + return nil, err + } + + return &result, nil +} + +func (b *backend) pathCRLRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + config, err := b.CRL(ctx, req.Storage) + if err != nil { + return nil, err + } + if config == nil { + return nil, nil + } + + return &logical.Response{ + Data: map[string]interface{}{ + "expiry": config.Expiry, + }, + }, nil +} + +func (b *backend) pathCRLWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + expiry := d.Get("expiry").(string) + + _, err := time.ParseDuration(expiry) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("Given expiry could not be decoded: %s", err)), nil + } + + config := &crlConfig{ + Expiry: expiry, + } + + entry, err := logical.StorageEntryJSON("config/crl", config) + if err != nil { + return nil, err + } + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + return nil, nil +} + +const pathConfigCRLHelpSyn = ` +Configure the CRL expiration. +` + +const pathConfigCRLHelpDesc = ` +This endpoint allows configuration of the CRL lifetime. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_urls.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_urls.go new file mode 100644 index 000000000..e3a0d6f96 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_config_urls.go @@ -0,0 +1,162 @@ +package pki + +import ( + "context" + "fmt" + + "github.com/asaskevich/govalidator" + "github.com/fatih/structs" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathConfigURLs(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "config/urls", + Fields: map[string]*framework.FieldSchema{ + "issuing_certificates": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Comma-separated list of URLs to be used +for the issuing certificate attribute`, + }, + + "crl_distribution_points": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Comma-separated list of URLs to be used +for the CRL distribution points attribute`, + }, + + "ocsp_servers": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `Comma-separated list of URLs to be used +for the OCSP servers attribute`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathWriteURL, + logical.ReadOperation: b.pathReadURL, + }, + + HelpSynopsis: pathConfigURLsHelpSyn, + HelpDescription: pathConfigURLsHelpDesc, + } +} + +func validateURLs(urls []string) string { + for _, curr := range urls { + if !govalidator.IsURL(curr) { + return curr + } + } + + return "" +} + +func getURLs(ctx context.Context, req *logical.Request) (*urlEntries, error) { + entry, err := req.Storage.Get(ctx, "urls") + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var entries urlEntries + if err := entry.DecodeJSON(&entries); err != nil { + return nil, err + } + + return &entries, nil +} + +func writeURLs(ctx context.Context, req *logical.Request, entries *urlEntries) error { + entry, err := logical.StorageEntryJSON("urls", entries) + if err != nil { + return err + } + if entry == nil { + return fmt.Errorf("unable to marshal entry into JSON") + } + + err = req.Storage.Put(ctx, entry) + if err != nil { + return err + } + + return nil +} + +func (b *backend) pathReadURL(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + entries, err := getURLs(ctx, req) + if err != nil { + return nil, err + } + if entries == nil { + return nil, nil + } + + resp := &logical.Response{ + Data: structs.New(entries).Map(), + } + + return resp, nil +} + +func (b *backend) pathWriteURL(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + entries, err := getURLs(ctx, req) + if err != nil { + return nil, err + } + if entries == nil { + entries = &urlEntries{ + IssuingCertificates: []string{}, + CRLDistributionPoints: []string{}, + OCSPServers: []string{}, + } + } + + if urlsInt, ok := data.GetOk("issuing_certificates"); ok { + entries.IssuingCertificates = urlsInt.([]string) + if badURL := validateURLs(entries.IssuingCertificates); badURL != "" { + return logical.ErrorResponse(fmt.Sprintf( + "invalid URL found in issuing certificates: %s", badURL)), nil + } + } + if urlsInt, ok := data.GetOk("crl_distribution_points"); ok { + entries.CRLDistributionPoints = urlsInt.([]string) + if badURL := validateURLs(entries.CRLDistributionPoints); badURL != "" { + return logical.ErrorResponse(fmt.Sprintf( + "invalid URL found in CRL distribution points: %s", badURL)), nil + } + } + if urlsInt, ok := data.GetOk("ocsp_servers"); ok { + entries.OCSPServers = urlsInt.([]string) + if badURL := validateURLs(entries.OCSPServers); badURL != "" { + return logical.ErrorResponse(fmt.Sprintf( + "invalid URL found in OCSP servers: %s", badURL)), nil + } + } + + return nil, writeURLs(ctx, req, entries) +} + +type urlEntries struct { + IssuingCertificates []string `json:"issuing_certificates" structs:"issuing_certificates" mapstructure:"issuing_certificates"` + CRLDistributionPoints []string `json:"crl_distribution_points" structs:"crl_distribution_points" mapstructure:"crl_distribution_points"` + OCSPServers []string `json:"ocsp_servers" structs:"ocsp_servers" mapstructure:"ocsp_servers"` +} + +const pathConfigURLsHelpSyn = ` +Set the URLs for the issuing CA, CRL distribution points, and OCSP servers. +` + +const pathConfigURLsHelpDesc = ` +This path allows you to set the issuing CA, CRL distribution points, and +OCSP server URLs that will be encoded into issued certificates. If these +values are not set, no such information will be encoded in the issued +certificates. To delete URLs, simply re-set the appropriate value with an +empty string. + +Multiple URLs can be specified for each type; use commas to separate them. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_fetch.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_fetch.go new file mode 100644 index 000000000..a38367ac6 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_fetch.go @@ -0,0 +1,276 @@ +package pki + +import ( + "context" + "encoding/pem" + "fmt" + "strings" + + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// Returns the CA in raw format +func pathFetchCA(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `ca(/pem)?`, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathFetchRead, + }, + + HelpSynopsis: pathFetchHelpSyn, + HelpDescription: pathFetchHelpDesc, + } +} + +// Returns the CA chain +func pathFetchCAChain(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `(cert/)?ca_chain`, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathFetchRead, + }, + + HelpSynopsis: pathFetchHelpSyn, + HelpDescription: pathFetchHelpDesc, + } +} + +// Returns the CRL in raw format +func pathFetchCRL(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `crl(/pem)?`, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathFetchRead, + }, + + HelpSynopsis: pathFetchHelpSyn, + HelpDescription: pathFetchHelpDesc, + } +} + +// Returns any valid (non-revoked) cert. Since "ca" fits the pattern, this path +// also handles returning the CA cert in a non-raw format. +func pathFetchValid(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `cert/(?P[0-9A-Fa-f-:]+)`, + Fields: map[string]*framework.FieldSchema{ + "serial": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `Certificate serial number, in colon- or +hyphen-separated octal`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathFetchRead, + }, + + HelpSynopsis: pathFetchHelpSyn, + HelpDescription: pathFetchHelpDesc, + } +} + +// This returns the CRL in a non-raw format +func pathFetchCRLViaCertPath(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `cert/crl`, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathFetchRead, + }, + + HelpSynopsis: pathFetchHelpSyn, + HelpDescription: pathFetchHelpDesc, + } +} + +// This returns the list of serial numbers for certs +func pathFetchListCerts(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "certs/?$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.pathFetchCertList, + }, + + HelpSynopsis: pathFetchHelpSyn, + HelpDescription: pathFetchHelpDesc, + } +} + +func (b *backend) pathFetchCertList(ctx context.Context, req *logical.Request, data *framework.FieldData) (response *logical.Response, retErr error) { + entries, err := req.Storage.List(ctx, "certs/") + if err != nil { + return nil, err + } + + return logical.ListResponse(entries), nil +} + +func (b *backend) pathFetchRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (response *logical.Response, retErr error) { + var serial, pemType, contentType string + var certEntry, revokedEntry *logical.StorageEntry + var funcErr error + var certificate []byte + var revocationTime int64 + response = &logical.Response{ + Data: map[string]interface{}{}, + } + + // Some of these need to return raw and some non-raw; + // this is basically handled by setting contentType or not. + // Errors don't cause an immediate exit, because the raw + // paths still need to return raw output. + + switch { + case req.Path == "ca" || req.Path == "ca/pem": + serial = "ca" + contentType = "application/pkix-cert" + if req.Path == "ca/pem" { + pemType = "CERTIFICATE" + } + case req.Path == "ca_chain" || req.Path == "cert/ca_chain": + serial = "ca_chain" + if req.Path == "ca_chain" { + contentType = "application/pkix-cert" + } + case req.Path == "crl" || req.Path == "crl/pem": + serial = "crl" + contentType = "application/pkix-crl" + if req.Path == "crl/pem" { + pemType = "X509 CRL" + } + case req.Path == "cert/crl": + serial = "crl" + pemType = "X509 CRL" + default: + serial = data.Get("serial").(string) + pemType = "CERTIFICATE" + } + if len(serial) == 0 { + response = logical.ErrorResponse("The serial number must be provided") + goto reply + } + + if serial == "ca_chain" { + caInfo, err := fetchCAInfo(ctx, req) + switch err.(type) { + case errutil.UserError: + response = logical.ErrorResponse(err.Error()) + goto reply + case errutil.InternalError: + retErr = err + goto reply + } + + caChain := caInfo.GetCAChain() + var certStr string + for _, ca := range caChain { + block := pem.Block{ + Type: "CERTIFICATE", + Bytes: ca.Bytes, + } + certStr = strings.Join([]string{certStr, strings.TrimSpace(string(pem.EncodeToMemory(&block)))}, "\n") + } + certificate = []byte(certStr) + goto reply + } + + certEntry, funcErr = fetchCertBySerial(ctx, req, req.Path, serial) + if funcErr != nil { + switch funcErr.(type) { + case errutil.UserError: + response = logical.ErrorResponse(funcErr.Error()) + goto reply + case errutil.InternalError: + retErr = funcErr + goto reply + } + } + if certEntry == nil { + response = nil + goto reply + } + + certificate = certEntry.Value + + if len(pemType) != 0 { + block := pem.Block{ + Type: pemType, + Bytes: certEntry.Value, + } + // This is convoluted on purpose to ensure that we don't have trailing + // newlines via various paths + certificate = []byte(strings.TrimSpace(string(pem.EncodeToMemory(&block)))) + } + + revokedEntry, funcErr = fetchCertBySerial(ctx, req, "revoked/", serial) + if funcErr != nil { + switch funcErr.(type) { + case errutil.UserError: + response = logical.ErrorResponse(funcErr.Error()) + goto reply + case errutil.InternalError: + retErr = funcErr + goto reply + } + } + if revokedEntry != nil { + var revInfo revocationInfo + err := revokedEntry.DecodeJSON(&revInfo) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("Error decoding revocation entry for serial %s: %s", serial, err)), nil + } + revocationTime = revInfo.RevocationTime + } + +reply: + switch { + case len(contentType) != 0: + response = &logical.Response{ + Data: map[string]interface{}{ + logical.HTTPContentType: contentType, + logical.HTTPRawBody: certificate, + }} + if retErr != nil { + if b.Logger().IsWarn() { + b.Logger().Warn("Possible error, but cannot return in raw response. Note that an empty CA probably means none was configured, and an empty CRL is possibly correct", "error", retErr) + } + } + retErr = nil + if len(certificate) > 0 { + response.Data[logical.HTTPStatusCode] = 200 + } else { + response.Data[logical.HTTPStatusCode] = 204 + } + case retErr != nil: + response = nil + return + case response == nil: + return + case response.IsError(): + return response, nil + default: + response.Data["certificate"] = string(certificate) + response.Data["revocation_time"] = revocationTime + } + + return +} + +const pathFetchHelpSyn = ` +Fetch a CA, CRL, CA Chain, or non-revoked certificate. +` + +const pathFetchHelpDesc = ` +This allows certificates to be fetched. If using the fetch/ prefix any non-revoked certificate can be fetched. + +Using "ca" or "crl" as the value fetches the appropriate information in DER encoding. Add "/pem" to either to get PEM encoding. + +Using "ca_chain" as the value fetches the certificate authority trust chain in PEM encoding. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_intermediate.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_intermediate.go new file mode 100644 index 000000000..0fb249b58 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_intermediate.go @@ -0,0 +1,254 @@ +package pki + +import ( + "context" + "encoding/base64" + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/certutil" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathGenerateIntermediate(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "intermediate/generate/" + framework.GenericNameRegex("exported"), + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathGenerateIntermediate, + }, + + HelpSynopsis: pathGenerateIntermediateHelpSyn, + HelpDescription: pathGenerateIntermediateHelpDesc, + } + + ret.Fields = addCACommonFields(map[string]*framework.FieldSchema{}) + ret.Fields = addCAKeyGenerationFields(ret.Fields) + ret.Fields["add_basic_constraints"] = &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `Whether to add a Basic Constraints +extension with CA: true. Only needed as a +workaround in some compatibility scenarios +with Active Directory Certificate Services.`, + } + + return ret +} + +func pathSetSignedIntermediate(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "intermediate/set-signed", + + Fields: map[string]*framework.FieldSchema{ + "certificate": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `PEM-format certificate. This must be a CA +certificate with a public key matching the +previously-generated key from the generation +endpoint.`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathSetSignedIntermediate, + }, + + HelpSynopsis: pathSetSignedIntermediateHelpSyn, + HelpDescription: pathSetSignedIntermediateHelpDesc, + } + + return ret +} + +func (b *backend) pathGenerateIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var err error + + exported, format, role, errorResp := b.getGenerationParams(data) + if errorResp != nil { + return errorResp, nil + } + + var resp *logical.Response + input := &dataBundle{ + role: role, + req: req, + apiData: data, + } + parsedBundle, err := generateIntermediateCSR(b, input) + if err != nil { + switch err.(type) { + case errutil.UserError: + return logical.ErrorResponse(err.Error()), nil + case errutil.InternalError: + return nil, err + } + } + + csrb, err := parsedBundle.ToCSRBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw CSR bundle to CSR bundle: {{err}}", err) + } + + resp = &logical.Response{ + Data: map[string]interface{}{}, + } + + switch format { + case "pem": + resp.Data["csr"] = csrb.CSR + if exported { + resp.Data["private_key"] = csrb.PrivateKey + resp.Data["private_key_type"] = csrb.PrivateKeyType + } + + case "pem_bundle": + resp.Data["csr"] = csrb.CSR + if exported { + resp.Data["csr"] = fmt.Sprintf("%s\n%s", csrb.PrivateKey, csrb.CSR) + resp.Data["private_key"] = csrb.PrivateKey + resp.Data["private_key_type"] = csrb.PrivateKeyType + } + + case "der": + resp.Data["csr"] = base64.StdEncoding.EncodeToString(parsedBundle.CSRBytes) + if exported { + resp.Data["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes) + resp.Data["private_key_type"] = csrb.PrivateKeyType + } + } + + if data.Get("private_key_format").(string) == "pkcs8" { + err = convertRespToPKCS8(resp) + if err != nil { + return nil, err + } + } + + cb := &certutil.CertBundle{} + cb.PrivateKey = csrb.PrivateKey + cb.PrivateKeyType = csrb.PrivateKeyType + + entry, err := logical.StorageEntryJSON("config/ca_bundle", cb) + if err != nil { + return nil, err + } + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + return resp, nil +} + +func (b *backend) pathSetSignedIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + cert := data.Get("certificate").(string) + + if cert == "" { + return logical.ErrorResponse("no certificate provided in the \"certificate\" parameter"), nil + } + + inputBundle, err := certutil.ParsePEMBundle(cert) + if err != nil { + switch err.(type) { + case errutil.InternalError: + return nil, err + default: + return logical.ErrorResponse(err.Error()), nil + } + } + + if inputBundle.Certificate == nil { + return logical.ErrorResponse("supplied certificate could not be successfully parsed"), nil + } + + cb := &certutil.CertBundle{} + entry, err := req.Storage.Get(ctx, "config/ca_bundle") + if err != nil { + return nil, err + } + if entry == nil { + return logical.ErrorResponse("could not find any existing entry with a private key"), nil + } + + err = entry.DecodeJSON(cb) + if err != nil { + return nil, err + } + + if len(cb.PrivateKey) == 0 || cb.PrivateKeyType == "" { + return logical.ErrorResponse("could not find an existing private key"), nil + } + + parsedCB, err := cb.ToParsedCertBundle() + if err != nil { + return nil, err + } + if parsedCB.PrivateKey == nil { + return nil, fmt.Errorf("saved key could not be parsed successfully") + } + + inputBundle.PrivateKey = parsedCB.PrivateKey + inputBundle.PrivateKeyType = parsedCB.PrivateKeyType + inputBundle.PrivateKeyBytes = parsedCB.PrivateKeyBytes + + if !inputBundle.Certificate.IsCA { + return logical.ErrorResponse("the given certificate is not marked for CA use and cannot be used with this backend"), nil + } + + if err := inputBundle.Verify(); err != nil { + return nil, errwrap.Wrapf("verification of parsed bundle failed: {{err}}", err) + } + + cb, err = inputBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw values into cert bundle: {{err}}", err) + } + + entry, err = logical.StorageEntryJSON("config/ca_bundle", cb) + if err != nil { + return nil, err + } + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + entry.Key = "certs/" + normalizeSerial(cb.SerialNumber) + entry.Value = inputBundle.CertificateBytes + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + // For ease of later use, also store just the certificate at a known + // location + entry.Key = "ca" + entry.Value = inputBundle.CertificateBytes + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + // Build a fresh CRL + err = buildCRL(ctx, b, req) + + return nil, err +} + +const pathGenerateIntermediateHelpSyn = ` +Generate a new CSR and private key used for signing. +` + +const pathGenerateIntermediateHelpDesc = ` +See the API documentation for more information. +` + +const pathSetSignedIntermediateHelpSyn = ` +Provide the signed intermediate CA cert. +` + +const pathSetSignedIntermediateHelpDesc = ` +See the API documentation for more information. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_issue_sign.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_issue_sign.go new file mode 100644 index 000000000..2785009b3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_issue_sign.go @@ -0,0 +1,364 @@ +package pki + +import ( + "context" + "encoding/base64" + "fmt" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/certutil" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathIssue(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "issue/" + framework.GenericNameRegex("role"), + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathIssue, + }, + + HelpSynopsis: pathIssueHelpSyn, + HelpDescription: pathIssueHelpDesc, + } + + ret.Fields = addNonCACommonFields(map[string]*framework.FieldSchema{}) + return ret +} + +func pathSign(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "sign/" + framework.GenericNameRegex("role"), + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathSign, + }, + + HelpSynopsis: pathSignHelpSyn, + HelpDescription: pathSignHelpDesc, + } + + ret.Fields = addNonCACommonFields(map[string]*framework.FieldSchema{}) + + ret.Fields["csr"] = &framework.FieldSchema{ + Type: framework.TypeString, + Default: "", + Description: `PEM-format CSR to be signed.`, + } + + return ret +} + +func pathSignVerbatim(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "sign-verbatim" + framework.OptionalParamRegex("role"), + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathSignVerbatim, + }, + + HelpSynopsis: pathSignHelpSyn, + HelpDescription: pathSignHelpDesc, + } + + ret.Fields = addNonCACommonFields(map[string]*framework.FieldSchema{}) + + ret.Fields["csr"] = &framework.FieldSchema{ + Type: framework.TypeString, + Default: "", + Description: `PEM-format CSR to be signed. Values will be +taken verbatim from the CSR, except for +basic constraints.`, + } + + ret.Fields["key_usage"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Default: []string{"DigitalSignature", "KeyAgreement", "KeyEncipherment"}, + Description: `A comma-separated string or list of key usages (not extended +key usages). Valid values can be found at +https://golang.org/pkg/crypto/x509/#KeyUsage +-- simply drop the "KeyUsage" part of the name. +To remove all key usages from being set, set +this value to an empty list.`, + } + + ret.Fields["ext_key_usage"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Default: []string{}, + Description: `A comma-separated string or list of extended key usages. Valid values can be found at +https://golang.org/pkg/crypto/x509/#ExtKeyUsage +-- simply drop the "ExtKeyUsage" part of the name. +To remove all key usages from being set, set +this value to an empty list.`, + } + + ret.Fields["ext_key_usage_oids"] = &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated string or list of extended key usage oids.`, + } + + return ret +} + +// pathIssue issues a certificate and private key from given parameters, +// subject to role restrictions +func (b *backend) pathIssue(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + roleName := data.Get("role").(string) + + // Get the role + role, err := b.getRole(ctx, req.Storage, roleName) + if err != nil { + return nil, err + } + if role == nil { + return logical.ErrorResponse(fmt.Sprintf("unknown role: %s", roleName)), nil + } + + if role.KeyType == "any" { + return logical.ErrorResponse("role key type \"any\" not allowed for issuing certificates, only signing"), nil + } + + return b.pathIssueSignCert(ctx, req, data, role, false, false) +} + +// pathSign issues a certificate from a submitted CSR, subject to role +// restrictions +func (b *backend) pathSign(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + roleName := data.Get("role").(string) + + // Get the role + role, err := b.getRole(ctx, req.Storage, roleName) + if err != nil { + return nil, err + } + if role == nil { + return logical.ErrorResponse(fmt.Sprintf("unknown role: %s", roleName)), nil + } + + return b.pathIssueSignCert(ctx, req, data, role, true, false) +} + +// pathSignVerbatim issues a certificate from a submitted CSR, *not* subject to +// role restrictions +func (b *backend) pathSignVerbatim(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + + roleName := data.Get("role").(string) + + // Get the role if one was specified + role, err := b.getRole(ctx, req.Storage, roleName) + if err != nil { + return nil, err + } + + entry := &roleEntry{ + TTL: b.System().DefaultLeaseTTL(), + MaxTTL: b.System().MaxLeaseTTL(), + AllowLocalhost: true, + AllowAnyName: true, + AllowIPSANs: true, + EnforceHostnames: false, + KeyType: "any", + UseCSRCommonName: true, + UseCSRSANs: true, + AllowedURISANs: []string{"*"}, + AllowedSerialNumbers: []string{"*"}, + GenerateLease: new(bool), + KeyUsage: data.Get("key_usage").([]string), + ExtKeyUsage: data.Get("ext_key_usage").([]string), + ExtKeyUsageOIDs: data.Get("ext_key_usage_oids").([]string), + } + + *entry.GenerateLease = false + + if role != nil { + if role.TTL > 0 { + entry.TTL = role.TTL + } + if role.MaxTTL > 0 { + entry.MaxTTL = role.MaxTTL + } + if role.GenerateLease != nil { + *entry.GenerateLease = *role.GenerateLease + } + entry.NoStore = role.NoStore + } + + if entry.MaxTTL > 0 && entry.TTL > entry.MaxTTL { + return logical.ErrorResponse(fmt.Sprintf("requested ttl of %s is greater than max ttl of %s", entry.TTL, entry.MaxTTL)), nil + } + + return b.pathIssueSignCert(ctx, req, data, entry, true, true) +} + +func (b *backend) pathIssueSignCert(ctx context.Context, req *logical.Request, data *framework.FieldData, role *roleEntry, useCSR, useCSRValues bool) (*logical.Response, error) { + format := getFormat(data) + if format == "" { + return logical.ErrorResponse( + `the "format" path parameter must be "pem", "der", or "pem_bundle"`), nil + } + + var caErr error + signingBundle, caErr := fetchCAInfo(ctx, req) + switch caErr.(type) { + case errutil.UserError: + return nil, errutil.UserError{Err: fmt.Sprintf( + "could not fetch the CA certificate (was one set?): %s", caErr)} + case errutil.InternalError: + return nil, errutil.InternalError{Err: fmt.Sprintf( + "error fetching CA certificate: %s", caErr)} + } + + input := &dataBundle{ + req: req, + apiData: data, + role: role, + signingBundle: signingBundle, + } + var parsedBundle *certutil.ParsedCertBundle + var err error + if useCSR { + parsedBundle, err = signCert(b, input, false, useCSRValues) + } else { + parsedBundle, err = generateCert(ctx, b, input, false) + } + if err != nil { + switch err.(type) { + case errutil.UserError: + return logical.ErrorResponse(err.Error()), nil + case errutil.InternalError: + return nil, err + } + } + + signingCB, err := signingBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw signing bundle to cert bundle: {{err}}", err) + } + + cb, err := parsedBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw cert bundle to cert bundle: {{err}}", err) + } + + respData := map[string]interface{}{ + "serial_number": cb.SerialNumber, + } + + switch format { + case "pem": + respData["issuing_ca"] = signingCB.Certificate + respData["certificate"] = cb.Certificate + if cb.CAChain != nil && len(cb.CAChain) > 0 { + respData["ca_chain"] = cb.CAChain + } + if !useCSR { + respData["private_key"] = cb.PrivateKey + respData["private_key_type"] = cb.PrivateKeyType + } + + case "pem_bundle": + respData["issuing_ca"] = signingCB.Certificate + respData["certificate"] = cb.ToPEMBundle() + if cb.CAChain != nil && len(cb.CAChain) > 0 { + respData["ca_chain"] = cb.CAChain + } + if !useCSR { + respData["private_key"] = cb.PrivateKey + respData["private_key_type"] = cb.PrivateKeyType + } + + case "der": + respData["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) + respData["issuing_ca"] = base64.StdEncoding.EncodeToString(signingBundle.CertificateBytes) + + var caChain []string + for _, caCert := range parsedBundle.CAChain { + caChain = append(caChain, base64.StdEncoding.EncodeToString(caCert.Bytes)) + } + if caChain != nil && len(caChain) > 0 { + respData["ca_chain"] = caChain + } + + if !useCSR { + respData["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes) + respData["private_key_type"] = cb.PrivateKeyType + } + } + + var resp *logical.Response + switch { + case role.GenerateLease == nil: + return nil, fmt.Errorf("generate lease in role is nil") + case *role.GenerateLease == false: + // If lease generation is disabled do not populate `Secret` field in + // the response + resp = &logical.Response{ + Data: respData, + } + default: + resp = b.Secret(SecretCertsType).Response( + respData, + map[string]interface{}{ + "serial_number": cb.SerialNumber, + }) + resp.Secret.TTL = parsedBundle.Certificate.NotAfter.Sub(time.Now()) + } + + if data.Get("private_key_format").(string) == "pkcs8" { + err = convertRespToPKCS8(resp) + if err != nil { + return nil, err + } + } + + if !role.NoStore { + err = req.Storage.Put(ctx, &logical.StorageEntry{ + Key: "certs/" + normalizeSerial(cb.SerialNumber), + Value: parsedBundle.CertificateBytes, + }) + if err != nil { + return nil, errwrap.Wrapf("unable to store certificate locally: {{err}}", err) + } + } + + if useCSR { + if role.UseCSRCommonName && data.Get("common_name").(string) != "" { + resp.AddWarning("the common_name field was provided but the role is set with \"use_csr_common_name\" set to true") + } + if role.UseCSRSANs && data.Get("alt_names").(string) != "" { + resp.AddWarning("the alt_names field was provided but the role is set with \"use_csr_sans\" set to true") + } + } + + return resp, nil +} + +const pathIssueHelpSyn = ` +Request a certificate using a certain role with the provided details. +` + +const pathIssueHelpDesc = ` +This path allows requesting a certificate to be issued according to the +policy of the given role. The certificate will only be issued if the +requested details are allowed by the role policy. + +This path returns a certificate and a private key. If you want a workflow +that does not expose a private key, generate a CSR locally and use the +sign path instead. +` + +const pathSignHelpSyn = ` +Request certificates using a certain role with the provided details. +` + +const pathSignHelpDesc = ` +This path allows requesting certificates to be issued according to the +policy of the given role. The certificate will only be issued if the +requested common name is allowed by the role policy. + +This path requires a CSR; if you want Vault to generate a private key +for you, use the issue path instead. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_revoke.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_revoke.go new file mode 100644 index 000000000..52ffac4b1 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_revoke.go @@ -0,0 +1,96 @@ +package pki + +import ( + "context" + "fmt" + "strings" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathRevoke(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `revoke`, + Fields: map[string]*framework.FieldSchema{ + "serial_number": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `Certificate serial number, in colon- or +hyphen-separated octal`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathRevokeWrite, + }, + + HelpSynopsis: pathRevokeHelpSyn, + HelpDescription: pathRevokeHelpDesc, + } +} + +func pathRotateCRL(b *backend) *framework.Path { + return &framework.Path{ + Pattern: `crl/rotate`, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathRotateCRLRead, + }, + + HelpSynopsis: pathRotateCRLHelpSyn, + HelpDescription: pathRotateCRLHelpDesc, + } +} + +func (b *backend) pathRevokeWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + serial := data.Get("serial_number").(string) + if len(serial) == 0 { + return logical.ErrorResponse("The serial number must be provided"), nil + } + + // We store and identify by lowercase colon-separated hex, but other + // utilities use dashes and/or uppercase, so normalize + serial = strings.Replace(strings.ToLower(serial), "-", ":", -1) + + b.revokeStorageLock.Lock() + defer b.revokeStorageLock.Unlock() + + return revokeCert(ctx, b, req, serial, false) +} + +func (b *backend) pathRotateCRLRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + b.revokeStorageLock.RLock() + defer b.revokeStorageLock.RUnlock() + + crlErr := buildCRL(ctx, b, req) + switch crlErr.(type) { + case errutil.UserError: + return logical.ErrorResponse(fmt.Sprintf("Error during CRL building: %s", crlErr)), nil + case errutil.InternalError: + return nil, errwrap.Wrapf("error encountered during CRL building: {{err}}", crlErr) + default: + return &logical.Response{ + Data: map[string]interface{}{ + "success": true, + }, + }, nil + } +} + +const pathRevokeHelpSyn = ` +Revoke a certificate by serial number. +` + +const pathRevokeHelpDesc = ` +This allows certificates to be revoked using its serial number. A root token is required. +` + +const pathRotateCRLHelpSyn = ` +Force a rebuild of the CRL. +` + +const pathRotateCRLHelpDesc = ` +Force a rebuild of the CRL. This can be used to remove expired certificates from it if no certificates have been revoked. A root token is required. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_roles.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_roles.go new file mode 100644 index 000000000..6f82474ea --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_roles.go @@ -0,0 +1,745 @@ +package pki + +import ( + "context" + "crypto/x509" + "fmt" + "strings" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/consts" + "github.com/hashicorp/vault/helper/parseutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathListRoles(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "roles/?$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ListOperation: b.pathRoleList, + }, + + HelpSynopsis: pathListRolesHelpSyn, + HelpDescription: pathListRolesHelpDesc, + } +} + +func pathRoles(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "roles/" + framework.GenericNameRegex("name"), + Fields: map[string]*framework.FieldSchema{ + "name": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "Name of the role", + }, + + "ttl": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: `The lease duration if no specific lease duration is +requested. The lease duration controls the expiration +of certificates issued by this backend. Defaults to +the value of max_ttl.`, + }, + + "max_ttl": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: "The maximum allowed lease duration", + }, + + "allow_localhost": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `Whether to allow "localhost" as a valid common +name in a request`, + }, + + "allowed_domains": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, clients can request certificates for +subdomains directly beneath these domains, including +the wildcard subdomains. See the documentation for more +information. This parameter accepts a comma-separated +string or list of domains.`, + }, + + "allow_bare_domains": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `If set, clients can request certificates +for the base domains themselves, e.g. "example.com". +This is a separate option as in some cases this can +be considered a security threat.`, + }, + + "allow_subdomains": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `If set, clients can request certificates for +subdomains of the CNs allowed by the other role options, +including wildcard subdomains. See the documentation for +more information.`, + }, + + "allow_glob_domains": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `If set, domains specified in "allowed_domains" +can include glob patterns, e.g. "ftp*.example.com". See +the documentation for more information.`, + }, + + "allow_any_name": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `If set, clients can request certificates for +any CN they like. See the documentation for more +information.`, + }, + + "enforce_hostnames": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, only valid host names are allowed for +CN and SANs. Defaults to true.`, + }, + + "allow_ip_sans": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, IP Subject Alternative Names are allowed. +Any valid IP is accepted.`, + }, + + "allowed_uri_sans": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, an array of allowed URIs to put in the URI Subject Alternative Names. +Any valid URI is accepted, these values support globbing.`, + }, + + "allowed_other_sans": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, an array of allowed other names to put in SANs. These values support globbing.`, + }, + + "allowed_serial_numbers": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, an array of allowed serial numbers to put in Subject. These values support globbing.`, + }, + + "server_flag": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, certificates are flagged for server auth use. +Defaults to true.`, + }, + + "client_flag": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, certificates are flagged for client auth use. +Defaults to true.`, + }, + + "code_signing_flag": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `If set, certificates are flagged for code signing +use. Defaults to false.`, + }, + + "email_protection_flag": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `If set, certificates are flagged for email +protection use. Defaults to false.`, + }, + + "key_type": &framework.FieldSchema{ + Type: framework.TypeString, + Default: "rsa", + Description: `The type of key to use; defaults to RSA. "rsa" +and "ec" are the only valid values.`, + }, + + "key_bits": &framework.FieldSchema{ + Type: framework.TypeInt, + Default: 2048, + Description: `The number of bits to use. You will almost +certainly want to change this if you adjust +the key_type.`, + }, + + "key_usage": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Default: []string{"DigitalSignature", "KeyAgreement", "KeyEncipherment"}, + Description: `A comma-separated string or list of key usages (not extended +key usages). Valid values can be found at +https://golang.org/pkg/crypto/x509/#KeyUsage +-- simply drop the "KeyUsage" part of the name. +To remove all key usages from being set, set +this value to an empty list.`, + }, + + "ext_key_usage": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Default: []string{}, + Description: `A comma-separated string or list of extended key usages. Valid values can be found at +https://golang.org/pkg/crypto/x509/#ExtKeyUsage +-- simply drop the "ExtKeyUsage" part of the name. +To remove all key usages from being set, set +this value to an empty list.`, + }, + + "ext_key_usage_oids": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated string or list of extended key usage oids.`, + }, + + "use_csr_common_name": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, when used with a signing profile, +the common name in the CSR will be used. This +does *not* include any requested Subject Alternative +Names. Defaults to true.`, + }, + + "use_csr_sans": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, when used with a signing profile, +the SANs in the CSR will be used. This does *not* +include the Common Name (cn). Defaults to true.`, + }, + + "ou": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, OU (OrganizationalUnit) will be set to +this value in certificates issued by this role.`, + }, + + "organization": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, O (Organization) will be set to +this value in certificates issued by this role.`, + }, + + "country": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Country will be set to +this value in certificates issued by this role.`, + }, + + "locality": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Locality will be set to +this value in certificates issued by this role.`, + }, + + "province": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Province will be set to +this value in certificates issued by this role.`, + }, + + "street_address": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Street Address will be set to +this value in certificates issued by this role.`, + }, + + "postal_code": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `If set, Postal Code will be set to +this value in certificates issued by this role.`, + }, + + "generate_lease": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: ` +If set, certificates issued/signed against this role will have Vault leases +attached to them. Defaults to "false". Certificates can be added to the CRL by +"vault revoke " when certificates are associated with leases. It can +also be done using the "pki/revoke" endpoint. However, when lease generation is +disabled, invoking "pki/revoke" would be the only way to add the certificates +to the CRL. When large number of certificates are generated with long +lifetimes, it is recommended that lease generation be disabled, as large amount of +leases adversely affect the startup time of Vault.`, + }, + "no_store": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: ` +If set, certificates issued/signed against this role will not be stored in the +storage backend. This can improve performance when issuing large numbers of +certificates. However, certificates issued in this way cannot be enumerated +or revoked, so this option is recommended only for certificates that are +non-sensitive, or extremely short-lived. This option implies a value of "false" +for "generate_lease".`, + }, + "require_cn": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set to false, makes the 'common_name' field optional while generating a certificate.`, + }, + "policy_identifiers": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated string or list of policy oids.`, + }, + "basic_constraints_valid_for_non_ca": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `Mark Basic Constraints valid when issuing non-CA certificates.`, + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.ReadOperation: b.pathRoleRead, + logical.UpdateOperation: b.pathRoleCreate, + logical.DeleteOperation: b.pathRoleDelete, + }, + + HelpSynopsis: pathRoleHelpSyn, + HelpDescription: pathRoleHelpDesc, + } +} + +func (b *backend) getRole(ctx context.Context, s logical.Storage, n string) (*roleEntry, error) { + entry, err := s.Get(ctx, "role/"+n) + if err != nil { + return nil, err + } + if entry == nil { + return nil, nil + } + + var result roleEntry + if err := entry.DecodeJSON(&result); err != nil { + return nil, err + } + + // Migrate existing saved entries and save back if changed + modified := false + if len(result.DeprecatedTTL) == 0 && len(result.Lease) != 0 { + result.DeprecatedTTL = result.Lease + result.Lease = "" + modified = true + } + if result.TTL == 0 && len(result.DeprecatedTTL) != 0 { + parsed, err := parseutil.ParseDurationSecond(result.DeprecatedTTL) + if err != nil { + return nil, err + } + result.TTL = parsed + result.DeprecatedTTL = "" + modified = true + } + if len(result.DeprecatedMaxTTL) == 0 && len(result.LeaseMax) != 0 { + result.DeprecatedMaxTTL = result.LeaseMax + result.LeaseMax = "" + modified = true + } + if result.MaxTTL == 0 && len(result.DeprecatedMaxTTL) != 0 { + parsed, err := parseutil.ParseDurationSecond(result.DeprecatedMaxTTL) + if err != nil { + return nil, err + } + result.MaxTTL = parsed + result.DeprecatedMaxTTL = "" + modified = true + } + if result.AllowBaseDomain { + result.AllowBaseDomain = false + result.AllowBareDomains = true + modified = true + } + if result.AllowedDomainsOld != "" { + result.AllowedDomains = strings.Split(result.AllowedDomainsOld, ",") + result.AllowedDomainsOld = "" + modified = true + } + if result.AllowedBaseDomain != "" { + found := false + for _, v := range result.AllowedDomains { + if v == result.AllowedBaseDomain { + found = true + break + } + } + if !found { + result.AllowedDomains = append(result.AllowedDomains, result.AllowedBaseDomain) + } + result.AllowedBaseDomain = "" + modified = true + } + + // Upgrade generate_lease in role + if result.GenerateLease == nil { + // All the new roles will have GenerateLease always set to a value. A + // nil value indicates that this role needs an upgrade. Set it to + // `true` to not alter its current behavior. + result.GenerateLease = new(bool) + *result.GenerateLease = true + modified = true + } + + // Upgrade key usages + if result.KeyUsageOld != "" { + result.KeyUsage = strings.Split(result.KeyUsageOld, ",") + result.KeyUsageOld = "" + modified = true + } + + // Upgrade OU + if result.OUOld != "" { + result.OU = strings.Split(result.OUOld, ",") + result.OUOld = "" + modified = true + } + + // Upgrade Organization + if result.OrganizationOld != "" { + result.Organization = strings.Split(result.OrganizationOld, ",") + result.OrganizationOld = "" + modified = true + } + + if modified && (b.System().LocalMount() || !b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary)) { + jsonEntry, err := logical.StorageEntryJSON("role/"+n, &result) + if err != nil { + return nil, err + } + if err := s.Put(ctx, jsonEntry); err != nil { + // Only perform upgrades on replication primary + if !strings.Contains(err.Error(), logical.ErrReadOnly.Error()) { + return nil, err + } + } + } + + return &result, nil +} + +func (b *backend) pathRoleDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + err := req.Storage.Delete(ctx, "role/"+data.Get("name").(string)) + if err != nil { + return nil, err + } + + return nil, nil +} + +func (b *backend) pathRoleRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + roleName := data.Get("name").(string) + if roleName == "" { + return logical.ErrorResponse("missing role name"), nil + } + + role, err := b.getRole(ctx, req.Storage, roleName) + if err != nil { + return nil, err + } + if role == nil { + return nil, nil + } + + resp := &logical.Response{ + Data: role.ToResponseData(), + } + return resp, nil +} + +func (b *backend) pathRoleList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + entries, err := req.Storage.List(ctx, "role/") + if err != nil { + return nil, err + } + + return logical.ListResponse(entries), nil +} + +func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var err error + name := data.Get("name").(string) + + entry := &roleEntry{ + MaxTTL: time.Duration(data.Get("max_ttl").(int)) * time.Second, + TTL: time.Duration(data.Get("ttl").(int)) * time.Second, + AllowLocalhost: data.Get("allow_localhost").(bool), + AllowedDomains: data.Get("allowed_domains").([]string), + AllowBareDomains: data.Get("allow_bare_domains").(bool), + AllowSubdomains: data.Get("allow_subdomains").(bool), + AllowGlobDomains: data.Get("allow_glob_domains").(bool), + AllowAnyName: data.Get("allow_any_name").(bool), + EnforceHostnames: data.Get("enforce_hostnames").(bool), + AllowIPSANs: data.Get("allow_ip_sans").(bool), + AllowedURISANs: data.Get("allowed_uri_sans").([]string), + ServerFlag: data.Get("server_flag").(bool), + ClientFlag: data.Get("client_flag").(bool), + CodeSigningFlag: data.Get("code_signing_flag").(bool), + EmailProtectionFlag: data.Get("email_protection_flag").(bool), + KeyType: data.Get("key_type").(string), + KeyBits: data.Get("key_bits").(int), + UseCSRCommonName: data.Get("use_csr_common_name").(bool), + UseCSRSANs: data.Get("use_csr_sans").(bool), + KeyUsage: data.Get("key_usage").([]string), + ExtKeyUsage: data.Get("ext_key_usage").([]string), + ExtKeyUsageOIDs: data.Get("ext_key_usage_oids").([]string), + OU: data.Get("ou").([]string), + Organization: data.Get("organization").([]string), + Country: data.Get("country").([]string), + Locality: data.Get("locality").([]string), + Province: data.Get("province").([]string), + StreetAddress: data.Get("street_address").([]string), + PostalCode: data.Get("postal_code").([]string), + GenerateLease: new(bool), + NoStore: data.Get("no_store").(bool), + RequireCN: data.Get("require_cn").(bool), + AllowedSerialNumbers: data.Get("allowed_serial_numbers").([]string), + PolicyIdentifiers: data.Get("policy_identifiers").([]string), + BasicConstraintsValidForNonCA: data.Get("basic_constraints_valid_for_non_ca").(bool), + } + + otherSANs := data.Get("allowed_other_sans").([]string) + if len(otherSANs) > 0 { + _, err := parseOtherSANs(otherSANs) + if err != nil { + return logical.ErrorResponse(errwrap.Wrapf("error parsing allowed_other_sans: {{err}}", err).Error()), nil + } + entry.AllowedOtherSANs = otherSANs + } + + // no_store implies generate_lease := false + if entry.NoStore { + *entry.GenerateLease = false + } else { + *entry.GenerateLease = data.Get("generate_lease").(bool) + } + + if entry.KeyType == "rsa" && entry.KeyBits < 2048 { + return logical.ErrorResponse("RSA keys < 2048 bits are unsafe and not supported"), nil + } + + if entry.MaxTTL > 0 && entry.TTL > entry.MaxTTL { + return logical.ErrorResponse( + `"ttl" value must be less than "max_ttl" value`, + ), nil + } + + if errResp := validateKeyTypeLength(entry.KeyType, entry.KeyBits); errResp != nil { + return errResp, nil + } + + if len(entry.ExtKeyUsageOIDs) > 0 { + for _, oidstr := range entry.ExtKeyUsageOIDs { + _, err := stringToOid(oidstr) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("%q could not be parsed as a valid oid for an extended key usage", oidstr)), nil + } + } + } + + if len(entry.PolicyIdentifiers) > 0 { + for _, oidstr := range entry.PolicyIdentifiers { + _, err := stringToOid(oidstr) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("%q could not be parsed as a valid oid for a policy identifier", oidstr)), nil + } + } + } + + // Store it + jsonEntry, err := logical.StorageEntryJSON("role/"+name, entry) + if err != nil { + return nil, err + } + if err := req.Storage.Put(ctx, jsonEntry); err != nil { + return nil, err + } + + return nil, nil +} + +func parseKeyUsages(input []string) int { + var parsedKeyUsages x509.KeyUsage + for _, k := range input { + switch strings.ToLower(strings.TrimSpace(k)) { + case "digitalsignature": + parsedKeyUsages |= x509.KeyUsageDigitalSignature + case "contentcommitment": + parsedKeyUsages |= x509.KeyUsageContentCommitment + case "keyencipherment": + parsedKeyUsages |= x509.KeyUsageKeyEncipherment + case "dataencipherment": + parsedKeyUsages |= x509.KeyUsageDataEncipherment + case "keyagreement": + parsedKeyUsages |= x509.KeyUsageKeyAgreement + case "certsign": + parsedKeyUsages |= x509.KeyUsageCertSign + case "crlsign": + parsedKeyUsages |= x509.KeyUsageCRLSign + case "encipheronly": + parsedKeyUsages |= x509.KeyUsageEncipherOnly + case "decipheronly": + parsedKeyUsages |= x509.KeyUsageDecipherOnly + } + } + + return int(parsedKeyUsages) +} + +func parseExtKeyUsages(role *roleEntry) certExtKeyUsage { + var parsedKeyUsages certExtKeyUsage + + if role.ServerFlag { + parsedKeyUsages |= serverAuthExtKeyUsage + } + + if role.ClientFlag { + parsedKeyUsages |= clientAuthExtKeyUsage + } + + if role.CodeSigningFlag { + parsedKeyUsages |= codeSigningExtKeyUsage + } + + if role.EmailProtectionFlag { + parsedKeyUsages |= emailProtectionExtKeyUsage + } + + for _, k := range role.ExtKeyUsage { + switch strings.ToLower(strings.TrimSpace(k)) { + case "any": + parsedKeyUsages |= anyExtKeyUsage + case "serverauth": + parsedKeyUsages |= serverAuthExtKeyUsage + case "clientauth": + parsedKeyUsages |= clientAuthExtKeyUsage + case "codesigning": + parsedKeyUsages |= codeSigningExtKeyUsage + case "emailprotection": + parsedKeyUsages |= emailProtectionExtKeyUsage + case "ipsecendsystem": + parsedKeyUsages |= ipsecEndSystemExtKeyUsage + case "ipsectunnel": + parsedKeyUsages |= ipsecTunnelExtKeyUsage + case "ipsecuser": + parsedKeyUsages |= ipsecUserExtKeyUsage + case "timestamping": + parsedKeyUsages |= timeStampingExtKeyUsage + case "ocspsigning": + parsedKeyUsages |= ocspSigningExtKeyUsage + case "microsoftservergatedcrypto": + parsedKeyUsages |= microsoftServerGatedCryptoExtKeyUsage + case "netscapeservergatedcrypto": + parsedKeyUsages |= netscapeServerGatedCryptoExtKeyUsage + } + } + + return parsedKeyUsages +} + +type roleEntry struct { + LeaseMax string `json:"lease_max"` + Lease string `json:"lease"` + DeprecatedMaxTTL string `json:"max_ttl" mapstructure:"max_ttl"` + DeprecatedTTL string `json:"ttl" mapstructure:"ttl"` + TTL time.Duration `json:"ttl_duration" mapstructure:"ttl_duration"` + MaxTTL time.Duration `json:"max_ttl_duration" mapstructure:"max_ttl_duration"` + AllowLocalhost bool `json:"allow_localhost" mapstructure:"allow_localhost"` + AllowedBaseDomain string `json:"allowed_base_domain" mapstructure:"allowed_base_domain"` + AllowedDomainsOld string `json:"allowed_domains,omit_empty"` + AllowedDomains []string `json:"allowed_domains_list" mapstructure:"allowed_domains"` + AllowBaseDomain bool `json:"allow_base_domain"` + AllowBareDomains bool `json:"allow_bare_domains" mapstructure:"allow_bare_domains"` + AllowTokenDisplayName bool `json:"allow_token_displayname" mapstructure:"allow_token_displayname"` + AllowSubdomains bool `json:"allow_subdomains" mapstructure:"allow_subdomains"` + AllowGlobDomains bool `json:"allow_glob_domains" mapstructure:"allow_glob_domains"` + AllowAnyName bool `json:"allow_any_name" mapstructure:"allow_any_name"` + EnforceHostnames bool `json:"enforce_hostnames" mapstructure:"enforce_hostnames"` + AllowIPSANs bool `json:"allow_ip_sans" mapstructure:"allow_ip_sans"` + ServerFlag bool `json:"server_flag" mapstructure:"server_flag"` + ClientFlag bool `json:"client_flag" mapstructure:"client_flag"` + CodeSigningFlag bool `json:"code_signing_flag" mapstructure:"code_signing_flag"` + EmailProtectionFlag bool `json:"email_protection_flag" mapstructure:"email_protection_flag"` + UseCSRCommonName bool `json:"use_csr_common_name" mapstructure:"use_csr_common_name"` + UseCSRSANs bool `json:"use_csr_sans" mapstructure:"use_csr_sans"` + KeyType string `json:"key_type" mapstructure:"key_type"` + KeyBits int `json:"key_bits" mapstructure:"key_bits"` + MaxPathLength *int `json:",omitempty" mapstructure:"max_path_length"` + KeyUsageOld string `json:"key_usage,omitempty"` + KeyUsage []string `json:"key_usage_list" mapstructure:"key_usage"` + ExtKeyUsage []string `json:"extended_key_usage_list" mapstructure:"extended_key_usage"` + OUOld string `json:"ou,omitempty"` + OU []string `json:"ou_list" mapstructure:"ou"` + OrganizationOld string `json:"organization,omitempty"` + Organization []string `json:"organization_list" mapstructure:"organization"` + Country []string `json:"country" mapstructure:"country"` + Locality []string `json:"locality" mapstructure:"locality"` + Province []string `json:"province" mapstructure:"province"` + StreetAddress []string `json:"street_address" mapstructure:"street_address"` + PostalCode []string `json:"postal_code" mapstructure:"postal_code"` + GenerateLease *bool `json:"generate_lease,omitempty"` + NoStore bool `json:"no_store" mapstructure:"no_store"` + RequireCN bool `json:"require_cn" mapstructure:"require_cn"` + AllowedOtherSANs []string `json:"allowed_other_sans" mapstructure:"allowed_other_sans"` + AllowedSerialNumbers []string `json:"allowed_serial_numbers" mapstructure:"allowed_serial_numbers"` + AllowedURISANs []string `json:"allowed_uri_sans" mapstructure:"allowed_uri_sans"` + PolicyIdentifiers []string `json:"policy_identifiers" mapstructure:"policy_identifiers"` + ExtKeyUsageOIDs []string `json:"ext_key_usage_oids" mapstructure:"ext_key_usage_oids"` + BasicConstraintsValidForNonCA bool `json:"basic_constraints_valid_for_non_ca" mapstructure:"basic_constraints_valid_for_non_ca"` + + // Used internally for signing intermediates + AllowExpirationPastCA bool +} + +func (r *roleEntry) ToResponseData() map[string]interface{} { + responseData := map[string]interface{}{ + "ttl": int64(r.TTL.Seconds()), + "max_ttl": int64(r.MaxTTL.Seconds()), + "allow_localhost": r.AllowLocalhost, + "allowed_domains": r.AllowedDomains, + "allow_bare_domains": r.AllowBareDomains, + "allow_token_displayname": r.AllowTokenDisplayName, + "allow_subdomains": r.AllowSubdomains, + "allow_glob_domains": r.AllowGlobDomains, + "allow_any_name": r.AllowAnyName, + "enforce_hostnames": r.EnforceHostnames, + "allow_ip_sans": r.AllowIPSANs, + "server_flag": r.ServerFlag, + "client_flag": r.ClientFlag, + "code_signing_flag": r.CodeSigningFlag, + "email_protection_flag": r.EmailProtectionFlag, + "use_csr_common_name": r.UseCSRCommonName, + "use_csr_sans": r.UseCSRSANs, + "key_type": r.KeyType, + "key_bits": r.KeyBits, + "key_usage": r.KeyUsage, + "ext_key_usage": r.ExtKeyUsage, + "ext_key_usage_oids": r.ExtKeyUsageOIDs, + "ou": r.OU, + "organization": r.Organization, + "country": r.Country, + "locality": r.Locality, + "province": r.Province, + "street_address": r.StreetAddress, + "postal_code": r.PostalCode, + "no_store": r.NoStore, + "allowed_other_sans": r.AllowedOtherSANs, + "allowed_serial_numbers": r.AllowedSerialNumbers, + "allowed_uri_sans": r.AllowedURISANs, + "require_cn": r.RequireCN, + "policy_identifiers": r.PolicyIdentifiers, + "basic_constraints_valid_for_non_ca": r.BasicConstraintsValidForNonCA, + } + if r.MaxPathLength != nil { + responseData["max_path_length"] = r.MaxPathLength + } + if r.GenerateLease != nil { + responseData["generate_lease"] = r.GenerateLease + } + return responseData +} + +const pathListRolesHelpSyn = `List the existing roles in this backend` + +const pathListRolesHelpDesc = `Roles will be listed by the role name.` + +const pathRoleHelpSyn = `Manage the roles that can be created with this backend.` + +const pathRoleHelpDesc = `This path lets you manage the roles that can be created with this backend.` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_root.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_root.go new file mode 100644 index 000000000..535e759d4 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_root.go @@ -0,0 +1,485 @@ +package pki + +import ( + "context" + "crypto/rand" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "fmt" + "reflect" + "strings" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/errutil" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathGenerateRoot(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "root/generate/" + framework.GenericNameRegex("exported"), + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathCAGenerateRoot, + }, + + HelpSynopsis: pathGenerateRootHelpSyn, + HelpDescription: pathGenerateRootHelpDesc, + } + + ret.Fields = addCACommonFields(map[string]*framework.FieldSchema{}) + ret.Fields = addCAKeyGenerationFields(ret.Fields) + ret.Fields = addCAIssueFields(ret.Fields) + + return ret +} + +func pathDeleteRoot(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "root", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.DeleteOperation: b.pathCADeleteRoot, + }, + + HelpSynopsis: pathDeleteRootHelpSyn, + HelpDescription: pathDeleteRootHelpDesc, + } + + return ret +} + +func pathSignIntermediate(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "root/sign-intermediate", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathCASignIntermediate, + }, + + HelpSynopsis: pathSignIntermediateHelpSyn, + HelpDescription: pathSignIntermediateHelpDesc, + } + + ret.Fields = addCACommonFields(map[string]*framework.FieldSchema{}) + ret.Fields = addCAIssueFields(ret.Fields) + + ret.Fields["csr"] = &framework.FieldSchema{ + Type: framework.TypeString, + Default: "", + Description: `PEM-format CSR to be signed.`, + } + + ret.Fields["use_csr_values"] = &framework.FieldSchema{ + Type: framework.TypeBool, + Default: false, + Description: `If true, then: +1) Subject information, including names and alternate +names, will be preserved from the CSR rather than +using values provided in the other parameters to +this path; +2) Any key usages requested in the CSR will be +added to the basic set of key usages used for CA +certs signed by this path; for instance, +the non-repudiation flag.`, + } + + return ret +} + +func pathSignSelfIssued(b *backend) *framework.Path { + ret := &framework.Path{ + Pattern: "root/sign-self-issued", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathCASignSelfIssued, + }, + + Fields: map[string]*framework.FieldSchema{ + "certificate": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `PEM-format self-issued certificate to be signed.`, + }, + }, + + HelpSynopsis: pathSignSelfIssuedHelpSyn, + HelpDescription: pathSignSelfIssuedHelpDesc, + } + + return ret +} + +func (b *backend) pathCADeleteRoot(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + return nil, req.Storage.Delete(ctx, "config/ca_bundle") +} + +func (b *backend) pathCAGenerateRoot(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var err error + + entry, err := req.Storage.Get(ctx, "config/ca_bundle") + if err != nil { + return nil, err + } + if entry != nil { + resp := &logical.Response{} + resp.AddWarning(fmt.Sprintf("Refusing to generate a root certificate over an existing root certificate. If you really want to destroy the original root certificate, please issue a delete against %sroot.", req.MountPoint)) + return resp, nil + } + + exported, format, role, errorResp := b.getGenerationParams(data) + if errorResp != nil { + return errorResp, nil + } + + maxPathLengthIface, ok := data.GetOk("max_path_length") + if ok { + maxPathLength := maxPathLengthIface.(int) + role.MaxPathLength = &maxPathLength + } + + input := &dataBundle{ + req: req, + apiData: data, + role: role, + } + parsedBundle, err := generateCert(ctx, b, input, true) + if err != nil { + switch err.(type) { + case errutil.UserError: + return logical.ErrorResponse(err.Error()), nil + case errutil.InternalError: + return nil, err + } + } + + cb, err := parsedBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw cert bundle to cert bundle: {{err}}", err) + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "expiration": int64(parsedBundle.Certificate.NotAfter.Unix()), + "serial_number": cb.SerialNumber, + }, + } + + switch format { + case "pem": + resp.Data["certificate"] = cb.Certificate + resp.Data["issuing_ca"] = cb.Certificate + if exported { + resp.Data["private_key"] = cb.PrivateKey + resp.Data["private_key_type"] = cb.PrivateKeyType + } + + case "pem_bundle": + resp.Data["issuing_ca"] = cb.Certificate + + if exported { + resp.Data["private_key"] = cb.PrivateKey + resp.Data["private_key_type"] = cb.PrivateKeyType + resp.Data["certificate"] = fmt.Sprintf("%s\n%s", cb.PrivateKey, cb.Certificate) + } else { + resp.Data["certificate"] = cb.Certificate + } + + case "der": + resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) + resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) + if exported { + resp.Data["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes) + resp.Data["private_key_type"] = cb.PrivateKeyType + } + } + + if data.Get("private_key_format").(string) == "pkcs8" { + err = convertRespToPKCS8(resp) + if err != nil { + return nil, err + } + } + + // Store it as the CA bundle + entry, err = logical.StorageEntryJSON("config/ca_bundle", cb) + if err != nil { + return nil, err + } + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + // Also store it as just the certificate identified by serial number, so it + // can be revoked + err = req.Storage.Put(ctx, &logical.StorageEntry{ + Key: "certs/" + normalizeSerial(cb.SerialNumber), + Value: parsedBundle.CertificateBytes, + }) + if err != nil { + return nil, errwrap.Wrapf("unable to store certificate locally: {{err}}", err) + } + + // For ease of later use, also store just the certificate at a known + // location + entry.Key = "ca" + entry.Value = parsedBundle.CertificateBytes + err = req.Storage.Put(ctx, entry) + if err != nil { + return nil, err + } + + // Build a fresh CRL + err = buildCRL(ctx, b, req) + if err != nil { + return nil, err + } + + if parsedBundle.Certificate.MaxPathLen == 0 { + resp.AddWarning("Max path length of the generated certificate is zero. This certificate cannot be used to issue intermediate CA certificates.") + } + + return resp, nil +} + +func (b *backend) pathCASignIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var err error + + format := getFormat(data) + if format == "" { + return logical.ErrorResponse( + `The "format" path parameter must be "pem" or "der"`, + ), nil + } + + role := &roleEntry{ + OU: data.Get("ou").([]string), + Organization: data.Get("organization").([]string), + Country: data.Get("country").([]string), + Locality: data.Get("locality").([]string), + Province: data.Get("province").([]string), + StreetAddress: data.Get("street_address").([]string), + PostalCode: data.Get("postal_code").([]string), + TTL: time.Duration(data.Get("ttl").(int)) * time.Second, + AllowLocalhost: true, + AllowAnyName: true, + AllowIPSANs: true, + EnforceHostnames: false, + KeyType: "any", + AllowedURISANs: []string{"*"}, + AllowedSerialNumbers: []string{"*"}, + AllowExpirationPastCA: true, + } + + if cn := data.Get("common_name").(string); len(cn) == 0 { + role.UseCSRCommonName = true + } + + var caErr error + signingBundle, caErr := fetchCAInfo(ctx, req) + switch caErr.(type) { + case errutil.UserError: + return nil, errutil.UserError{Err: fmt.Sprintf( + "could not fetch the CA certificate (was one set?): %s", caErr)} + case errutil.InternalError: + return nil, errutil.InternalError{Err: fmt.Sprintf( + "error fetching CA certificate: %s", caErr)} + } + + useCSRValues := data.Get("use_csr_values").(bool) + + maxPathLengthIface, ok := data.GetOk("max_path_length") + if ok { + maxPathLength := maxPathLengthIface.(int) + role.MaxPathLength = &maxPathLength + } + + input := &dataBundle{ + req: req, + apiData: data, + signingBundle: signingBundle, + role: role, + } + parsedBundle, err := signCert(b, input, true, useCSRValues) + if err != nil { + switch err.(type) { + case errutil.UserError: + return logical.ErrorResponse(err.Error()), nil + case errutil.InternalError: + return nil, err + } + } + + if err := parsedBundle.Verify(); err != nil { + return nil, errwrap.Wrapf("verification of parsed bundle failed: {{err}}", err) + } + + signingCB, err := signingBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw signing bundle to cert bundle: {{err}}", err) + } + + cb, err := parsedBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw cert bundle to cert bundle: {{err}}", err) + } + + resp := &logical.Response{ + Data: map[string]interface{}{ + "expiration": int64(parsedBundle.Certificate.NotAfter.Unix()), + "serial_number": cb.SerialNumber, + }, + } + + if signingBundle.Certificate.NotAfter.Before(parsedBundle.Certificate.NotAfter) { + resp.AddWarning("The expiration time for the signed certificate is after the CA's expiration time. If the new certificate is not treated as a root, validation paths with the certificate past the issuing CA's expiration time will fail.") + } + + switch format { + case "pem": + resp.Data["certificate"] = cb.Certificate + resp.Data["issuing_ca"] = signingCB.Certificate + if cb.CAChain != nil && len(cb.CAChain) > 0 { + resp.Data["ca_chain"] = cb.CAChain + } + + case "pem_bundle": + resp.Data["certificate"] = cb.ToPEMBundle() + resp.Data["issuing_ca"] = signingCB.Certificate + if cb.CAChain != nil && len(cb.CAChain) > 0 { + resp.Data["ca_chain"] = cb.CAChain + } + + case "der": + resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) + resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(signingBundle.CertificateBytes) + + var caChain []string + for _, caCert := range parsedBundle.CAChain { + caChain = append(caChain, base64.StdEncoding.EncodeToString(caCert.Bytes)) + } + if caChain != nil && len(caChain) > 0 { + resp.Data["ca_chain"] = cb.CAChain + } + } + + err = req.Storage.Put(ctx, &logical.StorageEntry{ + Key: "certs/" + normalizeSerial(cb.SerialNumber), + Value: parsedBundle.CertificateBytes, + }) + if err != nil { + return nil, errwrap.Wrapf("unable to store certificate locally: {{err}}", err) + } + + if parsedBundle.Certificate.MaxPathLen == 0 { + resp.AddWarning("Max path length of the signed certificate is zero. This certificate cannot be used to issue intermediate CA certificates.") + } + + return resp, nil +} + +func (b *backend) pathCASignSelfIssued(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { + var err error + + certPem := data.Get("certificate").(string) + block, _ := pem.Decode([]byte(certPem)) + if block == nil || len(block.Bytes) == 0 { + return logical.ErrorResponse("certificate could not be PEM-decoded"), nil + } + certs, err := x509.ParseCertificates(block.Bytes) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("error parsing certificate: %s", err)), nil + } + if len(certs) != 1 { + return logical.ErrorResponse(fmt.Sprintf("%d certificates found in PEM file, expected 1", len(certs))), nil + } + + cert := certs[0] + if !cert.IsCA { + return logical.ErrorResponse("given certificate is not a CA certificate"), nil + } + if !reflect.DeepEqual(cert.Issuer, cert.Subject) { + return logical.ErrorResponse("given certificate is not self-issued"), nil + } + + var caErr error + signingBundle, caErr := fetchCAInfo(ctx, req) + switch caErr.(type) { + case errutil.UserError: + return nil, errutil.UserError{Err: fmt.Sprintf( + "could not fetch the CA certificate (was one set?): %s", caErr)} + case errutil.InternalError: + return nil, errutil.InternalError{Err: fmt.Sprintf( + "error fetching CA certificate: %s", caErr)} + } + + signingCB, err := signingBundle.ToCertBundle() + if err != nil { + return nil, errwrap.Wrapf("error converting raw signing bundle to cert bundle: {{err}}", err) + } + + urls := &urlEntries{} + if signingBundle.URLs != nil { + urls = signingBundle.URLs + } + cert.IssuingCertificateURL = urls.IssuingCertificates + cert.CRLDistributionPoints = urls.CRLDistributionPoints + cert.OCSPServer = urls.OCSPServers + + newCert, err := x509.CreateCertificate(rand.Reader, cert, signingBundle.Certificate, cert.PublicKey, signingBundle.PrivateKey) + if err != nil { + return nil, errwrap.Wrapf("error signing self-issued certificate: {{err}}", err) + } + if len(newCert) == 0 { + return nil, fmt.Errorf("nil cert was created when signing self-issued certificate") + } + pemCert := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: newCert, + }) + + return &logical.Response{ + Data: map[string]interface{}{ + "certificate": strings.TrimSpace(string(pemCert)), + "issuing_ca": signingCB.Certificate, + }, + }, nil +} + +const pathGenerateRootHelpSyn = ` +Generate a new CA certificate and private key used for signing. +` + +const pathGenerateRootHelpDesc = ` +See the API documentation for more information. +` + +const pathDeleteRootHelpSyn = ` +Deletes the root CA key to allow a new one to be generated. +` + +const pathDeleteRootHelpDesc = ` +See the API documentation for more information. +` + +const pathSignIntermediateHelpSyn = ` +Issue an intermediate CA certificate based on the provided CSR. +` + +const pathSignIntermediateHelpDesc = ` +see the API documentation for more information. +` + +const pathSignSelfIssuedHelpSyn = ` +Signs another CA's self-issued certificate. +` + +const pathSignSelfIssuedHelpDesc = ` +Signs another CA's self-issued certificate. This is most often used for rolling roots; unless you know you need this you probably want to use sign-intermediate instead. + +Note that this is a very privileged operation and should be extremely restricted in terms of who is allowed to use it. All values will be taken directly from the incoming certificate and only verification that it is self-issued will be performed. + +Configured URLs for CRLs/OCSP/etc. will be copied over and the issuer will be this mount's CA cert. Other than that, all other values will be used verbatim. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_tidy.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_tidy.go new file mode 100644 index 000000000..4d9ea992d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/path_tidy.go @@ -0,0 +1,219 @@ +package pki + +import ( + "context" + "crypto/x509" + "fmt" + "sync/atomic" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +func pathTidy(b *backend) *framework.Path { + return &framework.Path{ + Pattern: "tidy", + Fields: map[string]*framework.FieldSchema{ + "tidy_cert_store": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `Set to true to enable tidying up +the certificate store`, + Default: false, + }, + + "tidy_revocation_list": &framework.FieldSchema{ + Type: framework.TypeBool, + Description: `Set to true to enable tidying up +the revocation list`, + Default: false, + }, + + "safety_buffer": &framework.FieldSchema{ + Type: framework.TypeDurationSecond, + Description: `The amount of extra time that must have passed +beyond certificate expiration before it is removed +from the backend storage and/or revocation list. +Defaults to 72 hours.`, + Default: 259200, //72h, but TypeDurationSecond currently requires defaults to be int + }, + }, + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.UpdateOperation: b.pathTidyWrite, + }, + + HelpSynopsis: pathTidyHelpSyn, + HelpDescription: pathTidyHelpDesc, + } +} + +func (b *backend) pathTidyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + safetyBuffer := d.Get("safety_buffer").(int) + tidyCertStore := d.Get("tidy_cert_store").(bool) + tidyRevocationList := d.Get("tidy_revocation_list").(bool) + + if safetyBuffer < 1 { + return logical.ErrorResponse("safety_buffer must be greater than zero"), nil + } + + bufferDuration := time.Duration(safetyBuffer) * time.Second + + if !atomic.CompareAndSwapUint32(b.tidyCASGuard, 0, 1) { + resp := &logical.Response{} + resp.AddWarning("Tidy operation already in progress.") + return resp, nil + } + + // Tests using framework will screw up the storage so make a locally + // scoped req to hold a reference + req = &logical.Request{ + Storage: req.Storage, + } + + go func() { + defer atomic.StoreUint32(b.tidyCASGuard, 0) + + // Don't cancel when the original client request goes away + ctx = context.Background() + + logger := b.Logger().Named("tidy") + + doTidy := func() error { + if tidyCertStore { + serials, err := req.Storage.List(ctx, "certs/") + if err != nil { + return errwrap.Wrapf("error fetching list of certs: {{err}}", err) + } + + for _, serial := range serials { + certEntry, err := req.Storage.Get(ctx, "certs/"+serial) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error fetching certificate %q: {{err}}", serial), err) + } + + if certEntry == nil { + logger.Warn("certificate entry is nil; tidying up since it is no longer useful for any server operations", "serial", serial) + if err := req.Storage.Delete(ctx, "certs/"+serial); err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting nil entry with serial %s: {{err}}", serial), err) + } + } + + if certEntry.Value == nil || len(certEntry.Value) == 0 { + logger.Warn("certificate entry has no value; tidying up since it is no longer useful for any server operations", "serial", serial) + if err := req.Storage.Delete(ctx, "certs/"+serial); err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting entry with nil value with serial %s: {{err}}", serial), err) + } + } + + cert, err := x509.ParseCertificate(certEntry.Value) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("unable to parse stored certificate with serial %q: {{err}}", serial), err) + } + + if time.Now().After(cert.NotAfter.Add(bufferDuration)) { + if err := req.Storage.Delete(ctx, "certs/"+serial); err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting serial %q from storage: {{err}}", serial), err) + } + } + } + } + + if tidyRevocationList { + b.revokeStorageLock.Lock() + defer b.revokeStorageLock.Unlock() + + tidiedRevoked := false + + revokedSerials, err := req.Storage.List(ctx, "revoked/") + if err != nil { + return errwrap.Wrapf("error fetching list of revoked certs: {{err}}", err) + } + + var revInfo revocationInfo + for _, serial := range revokedSerials { + revokedEntry, err := req.Storage.Get(ctx, "revoked/"+serial) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("unable to fetch revoked cert with serial %q: {{err}}", serial), err) + } + + if revokedEntry == nil { + logger.Warn("revoked entry is nil; tidying up since it is no longer useful for any server operations", "serial", serial) + if err := req.Storage.Delete(ctx, "revoked/"+serial); err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting nil revoked entry with serial %s: {{err}}", serial), err) + } + } + + if revokedEntry.Value == nil || len(revokedEntry.Value) == 0 { + logger.Warn("revoked entry has nil value; tidying up since it is no longer useful for any server operations", "serial", serial) + if err := req.Storage.Delete(ctx, "revoked/"+serial); err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting revoked entry with nil value with serial %s: {{err}}", serial), err) + } + } + + err = revokedEntry.DecodeJSON(&revInfo) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error decoding revocation entry for serial %q: {{err}}", serial), err) + } + + revokedCert, err := x509.ParseCertificate(revInfo.CertificateBytes) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("unable to parse stored revoked certificate with serial %q: {{err}}", serial), err) + } + + if time.Now().After(revokedCert.NotAfter.Add(bufferDuration)) { + if err := req.Storage.Delete(ctx, "revoked/"+serial); err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting serial %q from revoked list: {{err}}", serial), err) + } + tidiedRevoked = true + } + } + + if tidiedRevoked { + if err := buildCRL(ctx, b, req); err != nil { + return err + } + } + } + + return nil + } + + if err := doTidy(); err != nil { + logger.Error("error running tidy", "error", err) + return + } + }() + + resp := &logical.Response{} + resp.AddWarning("Tidy operation successfully started. Any information from the operation will be printed to Vault's server logs.") + return resp, nil +} + +const pathTidyHelpSyn = ` +Tidy up the backend by removing expired certificates, revocation information, +or both. +` + +const pathTidyHelpDesc = ` +This endpoint allows expired certificates and/or revocation information to be +removed from the backend, freeing up storage and shortening CRLs. + +For safety, this function is a noop if called without parameters; cleanup from +normal certificate storage must be enabled with 'tidy_cert_store' and cleanup +from revocation information must be enabled with 'tidy_revocation_list'. + +The 'safety_buffer' parameter is useful to ensure that clock skew amongst your +hosts cannot lead to a certificate being removed from the CRL while it is still +considered valid by other hosts (for instance, if their clocks are a few +minutes behind). The 'safety_buffer' parameter can be an integer number of +seconds or a string duration like "72h". + +All certificates and/or revocation information currently stored in the backend +will be checked when this endpoint is hit. The expiration of the +certificate/revocation information of each certificate being held in +certificate storage or in revocation information will then be checked. If the +current time, minus the value of 'safety_buffer', is greater than the +expiration, it will be removed. +` diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/secret_certs.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/secret_certs.go new file mode 100644 index 000000000..9c1734e31 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/secret_certs.go @@ -0,0 +1,52 @@ +package pki + +import ( + "context" + "fmt" + + "github.com/hashicorp/vault/logical" + "github.com/hashicorp/vault/logical/framework" +) + +// SecretCertsType is the name used to identify this type +const SecretCertsType = "pki" + +func secretCerts(b *backend) *framework.Secret { + return &framework.Secret{ + Type: SecretCertsType, + Fields: map[string]*framework.FieldSchema{ + "certificate": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The PEM-encoded concatenated certificate and +issuing certificate authority`, + }, + "private_key": &framework.FieldSchema{ + Type: framework.TypeString, + Description: "The PEM-encoded private key for the certificate", + }, + "serial": &framework.FieldSchema{ + Type: framework.TypeString, + Description: `The serial number of the certificate, for handy +reference`, + }, + }, + + Revoke: b.secretCredsRevoke, + } +} + +func (b *backend) secretCredsRevoke(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + if req.Secret == nil { + return nil, fmt.Errorf("secret is nil in request") + } + + serialInt, ok := req.Secret.InternalData["serial_number"] + if !ok { + return nil, fmt.Errorf("could not find serial in internal secret data") + } + + b.revokeStorageLock.Lock() + defer b.revokeStorageLock.Unlock() + + return revokeCert(ctx, b, req, serialInt.(string), true) +} diff --git a/vendor/github.com/hashicorp/vault/builtin/logical/pki/util.go b/vendor/github.com/hashicorp/vault/builtin/logical/pki/util.go new file mode 100644 index 000000000..3dffb536b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/builtin/logical/pki/util.go @@ -0,0 +1,7 @@ +package pki + +import "strings" + +func normalizeSerial(serial string) string { + return strings.Replace(strings.ToLower(serial), ":", "-", -1) +} 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 000000000..df424cee6 --- /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 000000000..3c072cee8 --- /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 000000000..fb30befb2 --- /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/compressutil/compress.go b/vendor/github.com/hashicorp/vault/helper/compressutil/compress.go new file mode 100644 index 000000000..a7fb87bcf --- /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 000000000..eee59d9c9 --- /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 000000000..06977d5d5 --- /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 000000000..c109977c5 --- /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 000000000..3337bd97b --- /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 000000000..0b95efb40 --- /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 000000000..0e5338c3c --- /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 000000000..218993492 --- /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 000000000..92e6cb152 --- /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/hclutil/hcl.go b/vendor/github.com/hashicorp/vault/helper/hclutil/hcl.go new file mode 100644 index 000000000..0b120367d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/hclutil/hcl.go @@ -0,0 +1,36 @@ +package hclutil + +import ( + "fmt" + + multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/hcl/hcl/ast" +) + +// CheckHCLKeys checks whether the keys in the AST list contains any of the valid keys provided. +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/helper/identity/identity.go b/vendor/github.com/hashicorp/vault/helper/identity/identity.go new file mode 100644 index 000000000..46789c035 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/identity/identity.go @@ -0,0 +1,65 @@ +package identity + +import ( + "fmt" + + proto "github.com/golang/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 000000000..bf3cfff55 --- /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 000000000..e26dcea22 --- /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 000000000..523f447da --- /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 000000000..d03ddef5f --- /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 000000000..50090749f --- /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 000000000..e220f8fb9 --- /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 000000000..221116648 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/keysutil/lock_manager.go @@ -0,0 +1,407 @@ +package keysutil + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/vault/helper/jsonutil" + "github.com/hashicorp/vault/helper/locksutil" + "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 { + useCache bool + // If caching is enabled, the map of name to in-memory policy cache + cache sync.Map + + keyLocks []*locksutil.LockEntry +} + +func NewLockManager(cacheDisabled bool) *LockManager { + lm := &LockManager{ + useCache: !cacheDisabled, + keyLocks: locksutil.CreateLocks(), + } + return lm +} + +func (lm *LockManager) CacheActive() bool { + return lm.useCache +} + +func (lm *LockManager) InvalidatePolicy(name string) { + lm.cache.Delete(name) +} + +// 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 { + 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 + + // Grab the exclusive lock as we'll be modifying disk + lock := locksutil.LockForKey(lm.keyLocks, name) + lock.Lock() + defer lock.Unlock() + + // If the policy is in cache, error out. Anywhere that would put it in the + // cache will also be protected by the mutex above, so we don't need to + // re-check the cache later. + _, ok := lm.cache.Load(name) + if ok { + return fmt.Errorf(fmt.Sprintf("key %q already exists", name)) + } + + // If the policy exists in storage, error out + p, err := lm.getPolicyFromStorage(ctx, storage, name) + if err != nil { + return err + } + if p != nil { + return fmt.Errorf(fmt.Sprintf("key %q already exists", name)) + } + + // We don't need to grab policy locks as we have ensured it doesn't already + // exist, so there will be no races as nothing else has this pointer. + + // 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 key %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) + } + + keyData.Policy.l = new(sync.RWMutex) + + // Update the cache to contain the restored policy + lm.cache.Store(name, keyData.Policy) + + return nil +} + +func (lm *LockManager) BackupPolicy(ctx context.Context, storage logical.Storage, name string) (string, error) { + var p *Policy + var err error + + // Backup writes information about when the bacup took place, so we get an + // exclusive lock here + lock := locksutil.LockForKey(lm.keyLocks, name) + lock.Lock() + defer lock.Unlock() + + pRaw, ok := lm.cache.Load(name) + if ok { + p = pRaw.(*Policy) + p.l.Lock() + defer p.l.Unlock() + } else { + // If the policy doesn't exit in storage, error out + p, err = lm.getPolicyFromStorage(ctx, storage, name) + if err != nil { + return "", err + } + if p == nil { + return "", fmt.Errorf(fmt.Sprintf("key %q not found", name)) + } + } + + if atomic.LoadUint32(&p.deleted) == 1 { + return "", fmt.Errorf(fmt.Sprintf("key %q not found", name)) + } + + backup, err := p.Backup(ctx, storage) + if err != nil { + return "", err + } + + return backup, nil +} + +// When the function returns, if caching was disabled, the Policy's lock must +// be unlocked when the caller is done (and it should not be re-locked). +func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest) (retP *Policy, retUpserted bool, retErr error) { + var p *Policy + var err error + + // Check if it's in our cache. If so, return right away. + pRaw, ok := lm.cache.Load(req.Name) + if ok { + p = pRaw.(*Policy) + if atomic.LoadUint32(&p.deleted) == 1 { + return nil, false, nil + } + return p, false, nil + } + + // We're not using the cache, or it wasn't found; get an exclusive lock. + // This ensures that any other process writing the actual storage will be + // finished before we load from storage. + lock := locksutil.LockForKey(lm.keyLocks, req.Name) + lock.Lock() + + // If we are using the cache, defer the lock unlock; otherwise we will + // return from here with the lock still held. + cleanup := func() { + switch { + // If using the cache we always unlock, the caller locks the policy + // themselves + case lm.useCache: + lock.Unlock() + // If not using the cache, if we aren't returning a policy the caller + // doesn't have a lock, so we must unlock + case retP == nil: + lock.Unlock() + } + } + + // Check the cache again + pRaw, ok = lm.cache.Load(req.Name) + if ok { + p = pRaw.(*Policy) + if atomic.LoadUint32(&p.deleted) == 1 { + cleanup() + return nil, false, nil + } + retP = p + cleanup() + return + } + + // Load it from storage + p, err = lm.getPolicyFromStorage(ctx, req.Storage, req.Name) + if err != nil { + cleanup() + return nil, false, err + } + // We don't need to lock the policy as there would be no other holders of + // the pointer + + 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 { + cleanup() + return nil, false, nil + } + + // We create the policy here, then at the end we do a LoadOrStore. If + // it's been loaded since we last checked the cache, we return an error + // to the user to let them know that their request can't be satisfied + // because we don't know if the parameters match. + + switch req.KeyType { + case KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305: + if req.Convergent && !req.Derived { + cleanup() + return nil, false, fmt.Errorf("convergent encryption requires derivation to be enabled") + } + + case KeyType_ECDSA_P256: + if req.Derived || req.Convergent { + cleanup() + return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType) + } + + case KeyType_ED25519: + if req.Convergent { + cleanup() + return 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 { + cleanup() + return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType) + } + + default: + cleanup() + return nil, false, fmt.Errorf("unsupported key type %v", req.KeyType) + } + + p = &Policy{ + l: new(sync.RWMutex), + Name: req.Name, + Type: req.KeyType, + Derived: req.Derived, + Exportable: req.Exportable, + AllowPlaintextBackup: req.AllowPlaintextBackup, + } + + 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 + } + } + + // Performs the actual persist and does setup + err = p.Rotate(ctx, req.Storage) + if err != nil { + cleanup() + return nil, false, err + } + + if lm.useCache { + lm.cache.Store(req.Name, p) + } else { + p.l = &lock.RWMutex + p.writeLocked = true + } + + // We don't need to worry about upgrading since it will be a new policy + retP = p + retUpserted = true + cleanup() + return + } + + if p.NeedsUpgrade() { + if err := p.Upgrade(ctx, req.Storage); err != nil { + cleanup() + return nil, false, err + } + } + + if lm.useCache { + lm.cache.Store(req.Name, p) + } else { + p.l = &lock.RWMutex + p.writeLocked = true + } + + retP = p + cleanup() + return +} + +func (lm *LockManager) DeletePolicy(ctx context.Context, storage logical.Storage, name string) error { + var p *Policy + var err error + + // We may be writing to disk, so grab an exclusive lock. This prevents bad + // behavior when the cache is turned off. We also lock the shared policy + // object to make sure no requests are in flight. + lock := locksutil.LockForKey(lm.keyLocks, name) + lock.Lock() + defer lock.Unlock() + + pRaw, ok := lm.cache.Load(name) + if ok { + p = pRaw.(*Policy) + p.l.Lock() + defer p.l.Unlock() + } + + if p == nil { + p, err = lm.getPolicyFromStorage(ctx, storage, name) + if err != nil { + return err + } + if p == nil { + return fmt.Errorf("could not delete key; not found") + } + } + + if !p.DeletionAllowed { + return fmt.Errorf("deletion is not allowed for this key") + } + + atomic.StoreUint32(&p.deleted, 1) + + lm.cache.Delete(name) + + err = storage.Delete(ctx, "policy/"+name) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting key %q: {{err}}", name), err) + } + + err = storage.Delete(ctx, "archive/"+name) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("error deleting key %q archive: {{err}}", name), err) + } + + return nil +} + +func (lm *LockManager) getPolicyFromStorage(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 000000000..edba36a73 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/keysutil/policy.go @@ -0,0 +1,1463 @@ +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" + "errors" + "fmt" + "io" + "math/big" + "path" + "strconv" + "strings" + "sync" + "sync/atomic" + "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{ + l: new(sync.RWMutex), + 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, + } +} + +// 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.l = new(sync.RWMutex) + + return &policy, nil +} + +// Policy is the struct used to store metadata +type Policy struct { + // This is a pointer on purpose: if we are running with cache disabled we + // need to actually swap in the lock manager's lock for this policy with + // the local lock. + l *sync.RWMutex + // writeLocked allows us to implement Lock() and Unlock() + writeLocked bool + // Stores whether it's been deleted. This acts as a guard for operations + // that may write data, e.g. if one request rotates and that request is + // served after a delete. + deleted uint32 + + 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 version prefix strings and the split + // version template. + versionPrefixCache sync.Map +} + +func (p *Policy) Lock(exclusive bool) { + if exclusive { + p.l.Lock() + p.writeLocked = true + } else { + p.l.RLock() + } +} + +func (p *Policy) Unlock() { + if p.writeLocked { + p.writeLocked = false + p.l.Unlock() + } else { + p.l.RUnlock() + } +} + +// 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) { + if atomic.LoadUint32(&p.deleted) == 1 { + return errors.New("key has been deleted, not persisting") + } + + // 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 000000000..e0c2fcdd8 --- /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 000000000..3e7e4766d --- /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/mlock/mlock.go b/vendor/github.com/hashicorp/vault/helper/mlock/mlock.go new file mode 100644 index 000000000..1675633d3 --- /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 000000000..8084963f7 --- /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 000000000..af0a69d48 --- /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 000000000..ae8c58ba7 --- /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/pathmanager/pathmanager.go b/vendor/github.com/hashicorp/vault/helper/pathmanager/pathmanager.go new file mode 100644 index 000000000..e0e39445b --- /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 000000000..eef4c5ed0 --- /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 000000000..bb0f367d6 --- /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 000000000..eba067762 --- /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 000000000..c10a9055e --- /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 000000000..337c7b736 --- /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 000000000..436e169fe --- /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 000000000..d43f77806 --- /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 000000000..f6d9f6687 --- /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 000000000..44526c08e --- /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 000000000..4fd562058 --- /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 000000000..67c05b9b1 --- /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 000000000..2e82344ad --- /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 000000000..8d8a998c9 --- /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 000000000..a77e60d15 --- /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 000000000..08b3ebd0c --- /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 000000000..9c84a1d47 --- /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 000000000..0d9567eb5 --- /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 000000000..9e8b6fa19 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/cors.go @@ -0,0 +1,67 @@ +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() + + // 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() { + h.ServeHTTP(w, req) + return + } + + origin := req.Header.Get("Origin") + requestMethod := req.Header.Get("Access-Control-Request-Method") + + if 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 000000000..a9be673cb --- /dev/null +++ b/vendor/github.com/hashicorp/vault/http/handler.go @@ -0,0 +1,577 @@ +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 + req.SetTokenEntry(te) + } + } + + 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 000000000..1c3a9560f --- /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 000000000..7b31c8751 --- /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 000000000..c64ac582a --- /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 000000000..74456b943 --- /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 000000000..be67f2fa2 --- /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 000000000..f13ff5d3b --- /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 000000000..98eb04ac1 --- /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 000000000..54149c448 --- /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 000000000..d86d7f2d0 --- /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 000000000..2299006c9 --- /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 000000000..68f856f4b --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/auth.go @@ -0,0 +1,92 @@ +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"` + + // TokenPolicies and IdentityPolicies break down the list in Policies to + // help determine where a policy was sourced + TokenPolicies []string `json:"token_policies" mapstructure:"token_policies" structs:"token_policies"` + IdentityPolicies []string `json:"identity_policies" mapstructure:"identity_policies" structs:"identity_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 000000000..a504b10c3 --- /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 000000000..00a64092b --- /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 000000000..3c674e365 --- /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 000000000..ac66dad86 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/framework/field_data.go @@ -0,0 +1,294 @@ +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() +} + +// GetFirst gets the value for the given field names, in order from first +// to last. This can be useful for fields with a current name, and one or +// more deprecated names. The second return value will be false if the keys +// are invalid or the keys are not set at all. +func (d *FieldData) GetFirst(k ...string) (interface{}, bool) { + for _, v := range k { + if result, ok := d.GetOk(v); ok { + return result, ok + } + } + return nil, false +} + +// 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 000000000..d447eabfb --- /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 000000000..4f55ae0de --- /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 000000000..e53dd196c --- /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 000000000..83aa0bafa --- /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 000000000..beaed52d6 --- /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 000000000..089cf7f2c --- /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 000000000..616a055c8 --- /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 000000000..3abdd624c --- /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 000000000..a00a3241c --- /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 000000000..c8fa3b871 --- /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 000000000..0deed7254 --- /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 000000000..914a6ada0 --- /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 000000000..90c089476 --- /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 000000000..a3456e967 --- /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/request.go b/vendor/github.com/hashicorp/vault/logical/request.go new file mode 100644 index 000000000..4c395370d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/request.go @@ -0,0 +1,295 @@ +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"` + + // Cached token entry. This avoids another lookup in request handling when + // we've already looked it up at http handling time. Note that this token + // has not been "used", as in it will not properly take into account use + // count limitations. As a result this field should only ever be used for + // transport to a function that would otherwise do a lookup and then + // properly use the token. + tokenEntry *TokenEntry + + // 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 +} + +func (r *Request) TokenEntry() *TokenEntry { + return r.tokenEntry +} + +func (r *Request) SetTokenEntry(te *TokenEntry) { + r.tokenEntry = te +} + +// 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 000000000..723f88e7d --- /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 000000000..803ae9fbd --- /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 000000000..a2128d868 --- /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 000000000..116fd301c --- /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 000000000..e0ff75f14 --- /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 000000000..3fbcb6719 --- /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 000000000..7c7738996 --- /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/token.go b/vendor/github.com/hashicorp/vault/logical/token.go new file mode 100644 index 000000000..337791e48 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/token.go @@ -0,0 +1,119 @@ +package logical + +import ( + "time" + + sockaddr "github.com/hashicorp/go-sockaddr" +) + +// 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", + } +} 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 000000000..2bd816bb3 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/logical/translate_response.go @@ -0,0 +1,149 @@ +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, + TokenPolicies: input.Auth.TokenPolicies, + IdentityPolicies: input.Auth.IdentityPolicies, + 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, + TokenPolicies: input.Auth.TokenPolicies, + IdentityPolicies: input.Auth.IdentityPolicies, + 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"` + TokenPolicies []string `json:"token_policies,omitempty"` + IdentityPolicies []string `json:"identity_policies,omitempty"` + 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 000000000..4e2e5a5d6 --- /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 000000000..027430568 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/physical/inmem/inmem.go @@ -0,0 +1,224 @@ +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, + failGet: new(uint32), + failPut: new(uint32), + failDelete: new(uint32), + failList: new(uint32), + } + 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, + failGet: new(uint32), + failPut: new(uint32), + failDelete: new(uint32), + failList: new(uint32), + }, + } + 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 000000000..675510070 --- /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 000000000..7aa9fab98 --- /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 000000000..c7a37fc3e --- /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 000000000..58ac9739a --- /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 000000000..da505a4f1 --- /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 000000000..375d9053e --- /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 000000000..5c43e57dc --- /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 000000000..c403cee7f --- /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 000000000..2a4774d2e --- /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 000000000..05ad66261 --- /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 000000000..700f963fe --- /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 000000000..62e739a66 --- /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 000000000..a4d394f9e --- /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 000000000..61ca9c51b --- /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 000000000..9004a3c71 --- /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 000000000..62b415af8 --- /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 [{{username}}] WITH PASSWORD = '{{password}}' +` 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 000000000..a36f1a868 --- /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 000000000..36dd0036a --- /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 000000000..45f6fa0ad --- /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 000000000..38685d0be --- /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 000000000..f186915fc --- /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 000000000..2f9cc7d19 --- /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 000000000..42257053c --- /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 000000000..0bc3bc4e8 --- /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 000000000..04650868c --- /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 000000000..76c245e79 --- /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 000000000..bc7920522 --- /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 *logical.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 000000000..99841488d --- /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 000000000..ae6f48ecc --- /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 000000000..ca8383ea8 --- /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 000000000..a50320dc0 --- /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 000000000..7f8a31381 --- /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 000000000..84e6e7475 --- /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 000000000..001bd3b71 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/barrier_aes_gcm.go @@ -0,0 +1,900 @@ +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() + sealed := b.sealed + b.l.RUnlock() + return 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() + if b.sealed { + b.l.RUnlock() + return nil, ErrBarrierSealed + } + + term := b.keyring.ActiveTerm() + primary, err := b.aeadForTerm(term) + if err != nil { + b.l.RUnlock() + return nil, err + } + + ciphertext := b.encrypt(key, term, primary, plaintext) + b.l.RUnlock() + 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() + if b.sealed { + b.l.RUnlock() + return nil, ErrBarrierSealed + } + + // Decrypt the ciphertext + plain, err := b.decryptKeyring(key, ciphertext) + if err != nil { + b.l.RUnlock() + return nil, errwrap.Wrapf("decryption failed: {{err}}", err) + } + + b.l.RUnlock() + 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 000000000..cc1a4251c --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/barrier_view.go @@ -0,0 +1,145 @@ +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 entry == nil { + return errors.New("cannot write nil entry") + } + + 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 000000000..c3ffa9ee9 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/capabilities.go @@ -0,0 +1,75 @@ +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 { + c.logger.Warn("permission denied as the entity on the token is disabled") + return nil, logical.ErrPermissionDenied + } + if te != nil && te.EntityID != "" && entity == nil { + c.logger.Warn("permission denied as the entity on the token is invalid") + 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 000000000..4919b0b2b --- /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 000000000..cab0cb373 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/core.go @@ -0,0 +1,1437 @@ +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), + keepHALockOnStepDown: 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, + Enabled: new(uint32), + } + + 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 + } + + acl, te, entity, identityPolicies, 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, + Policies: identityPolicies, + IdentityPolicies: identityPolicies, + } + if te != nil { + auth.TokenPolicies = te.Policies + auth.Policies = append(te.Policies, identityPolicies...) + 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 { + c.logger.Warn("permission denied as the entity on the token is disabled") + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + c.stateLock.RUnlock() + return retErr + } + if te != nil && te.EntityID != "" && entity == nil { + c.logger.Warn("permission denied as the entity on the token is invalid") + 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 000000000..c389a6e6d --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/cors.go @@ -0,0 +1,161 @@ +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/") + + enabled := atomic.LoadUint32(c.corsConfig.Enabled) + localConfig := &CORSConfig{ + Enabled: &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 + } + + if newConfig.Enabled == nil { + newConfig.Enabled = new(uint32) + } + + 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 000000000..2b0aa7840 --- /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 000000000..7924a4017 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/expiration.go @@ -0,0 +1,1422 @@ +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 +) + +type pendingInfo struct { + exportLeaseTimes *leaseEntry + timer *time.Timer +} + +// 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]pendingInfo + 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]pendingInfo), + tidyLock: new(int32), + + // new instances of the expiration manager will go immediately into + // restore mode + restoreMode: new(int32), + restoreLocks: locksutil.CreateLocks(), + quitCh: make(chan struct{}), + + coreStateLock: &c.stateLock, + quitContext: c.activeContext, + leaseCheckCounter: new(uint32), + + logLeaseExpirations: os.Getenv("VAULT_SKIP_LOGGING_LEASE_EXPIRATIONS") == "", + } + *exp.restoreMode = 1 + + 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 + + logger := m.logger.Named("tidy") + + if !atomic.CompareAndSwapInt32(m.tidyLock, 0, 1) { + logger.Warn("tidy operation on leases is already in progress") + return nil + } + + defer atomic.CompareAndSwapInt32(m.tidyLock, 1, 0) + + logger.Info("beginning tidy operation on leases") + defer 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 { + 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 == "" { + 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 { + 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 + } + + 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 + } + + logger.Info("number of leases scanned", "count", countLease) + logger.Info("number of leases which had empty tokens", "count", deletedCountEmptyToken) + logger.Info("number of leases which had invalid tokens", "count", deletedCountInvalidToken) + 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 _, pending := range m.pending { + pending.timer.Stop() + } + m.pending = make(map[string]pendingInfo) + 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 pending, ok := m.pending[leaseID]; ok { + pending.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 *logical.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() + + { + m.pendingLock.Lock() + if err := m.persistEntry(le); err != nil { + m.pendingLock.Unlock() + return err + } + + m.updatePendingInternal(le, 0) + m.pendingLock.Unlock() + } + } + } + + // 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() + + { + m.pendingLock.Lock() + if err := m.persistEntry(le); err != nil { + m.pendingLock.Unlock() + return nil, err + } + + // Update the expiration time + m.updatePendingInternal(le, resp.Secret.LeaseTotal()) + m.pendingLock.Unlock() + } + + // 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() + + { + m.pendingLock.Lock() + if err := m.persistEntry(le); err != nil { + m.pendingLock.Unlock() + return nil, err + } + + // Update the expiration time + m.updatePendingInternal(le, resp.Auth.LeaseTotal()) + m.pendingLock.Unlock() + } + + 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()) + + m.pendingLock.RLock() + val := m.pending[leaseID] + m.pendingLock.RUnlock() + + if val.exportLeaseTimes != nil { + return val.exportLeaseTimes, nil + } + + // Load the entry + le, err := m.loadEntry(leaseID) + if err != nil { + return nil, err + } + if le == nil { + return nil, nil + } + + return m.leaseTimesForExport(le), nil +} + +// Returns lease times for outside callers based on the full leaseEntry passed in +func (m *ExpirationManager) leaseTimesForExport(le *leaseEntry) *leaseEntry { + 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 +} + +// 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() + + m.updatePendingInternal(le, leaseTotal) +} + +// updatePendingInternal is the locked version of updatePending; do not call +// this without a write lock on m.pending +func (m *ExpirationManager) updatePendingInternal(le *leaseEntry, leaseTotal time.Duration) { + // Check for an existing timer + pending, 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 { + pending.timer.Stop() + delete(m.pending, le.LeaseID) + } + return + } + + // Create entry if it does not exist or reset if it does + if ok { + pending.timer.Reset(leaseTotal) + } else { + timer := time.AfterFunc(leaseTotal, func() { + m.expireID(le.LeaseID) + }) + pending = pendingInfo{ + timer: timer, + } + } + + // Extend the timer by the lease total + pending.exportLeaseTimes = m.leaseTimesForExport(le) + + m.pending[le.LeaseID] = pending +} + +// 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 *logical.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 000000000..37f408e02 --- /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 000000000..014ebeb70 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/ha.go @@ -0,0 +1,737 @@ +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() + standby := c.standby + c.stateLock.RUnlock() + return standby, nil +} + +// Leader is used to get the current active leader +func (c *Core) Leader() (isLeader bool, leaderAddr, clusterAddr string, err error) { + // Check if HA enabled. We don't need the lock for this check as it's set + // on startup and never modified + if c.ha == nil { + return false, "", "", ErrHANotEnabled + } + + c.stateLock.RLock() + + // Check if sealed + if c.sealed { + c.stateLock.RUnlock() + return false, "", "", consts.ErrSealed + } + + // Check if we are the leader + if !c.standby { + c.stateLock.RUnlock() + return true, c.redirectAddr, c.clusterAddr, nil + } + + // Initialize a lock + lock, err := c.ha.LockWith(coreLockPath, "read") + if err != nil { + c.stateLock.RUnlock() + return false, "", "", err + } + + // Read the value + held, leaderUUID, err := lock.Value() + if err != nil { + c.stateLock.RUnlock() + return false, "", "", err + } + if !held { + c.stateLock.RUnlock() + 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 != "" { + c.stateLock.RUnlock() + return false, localRedirAddr, localClusterAddr, nil + } + + c.logger.Trace("found new active node information, refreshing") + + defer c.stateLock.RUnlock() + 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, identityPolicies, 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, + Policies: identityPolicies, + IdentityPolicies: identityPolicies, + } + if te != nil { + auth.TokenPolicies = te.Policies + auth.Policies = append(te.Policies, identityPolicies...) + 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 { + c.logger.Warn("permission denied as the entity on the token is disabled") + retErr = multierror.Append(retErr, logical.ErrPermissionDenied) + c.stateLock.RUnlock() + return retErr + } + + if te != nil && te.EntityID != "" && entity == nil { + c.logger.Warn("permission denied as the entity on the token is invalid") + 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) + opCount := new(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) + opCount := new(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 000000000..20d7ea0b6 --- /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 000000000..6faddace5 --- /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 000000000..1f578df19 --- /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 000000000..5096ed0b0 --- /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 000000000..047fc4799 --- /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 000000000..3a56b4626 --- /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 000000000..3fce0bf35 --- /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 000000000..0f9435cf7 --- /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 000000000..9399e6259 --- /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 000000000..e8b4cc1b0 --- /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 000000000..659858e90 --- /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 000000000..fd6564790 --- /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 000000000..08055ddb3 --- /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 000000000..3a40da251 --- /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 000000000..eda157594 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/logical_system.go @@ -0,0 +1,4326 @@ +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) { + go func() { + err := b.Core.expiration.Tidy() + if err != nil { + b.Backend.Logger().Error("failed to tidy leases", "error", err) + return + } + }() + + resp := &logical.Response{} + resp.AddWarning("Tidy operation successfully started. Any information from the operation will be printed to Vault's server logs.") + return resp, nil +} + +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 { + if !strings.HasSuffix(req.Path, "capabilities-self") && errwrap.Contains(err, logical.ErrPermissionDenied.Error()) { + return nil, &logical.StatusBadRequest{Err: "invalid token"} + } + 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 + var te *logical.TokenEntry + // Load the ACL policies so we can walk the prefix for this mount + acl, te, entity, _, err = b.Core.fetchACLTokenEntryAndEntity(req) + if err != nil { + return nil, err + } + if entity != nil && entity.Disabled { + b.logger.Warn("permission denied as the entity on the token is disabled") + return nil, logical.ErrPermissionDenied + } + if te != nil && te.EntityID != "" && entity == nil { + b.logger.Warn("permission denied as the entity on the token is invalid") + 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, te, entity, _, err := b.Core.fetchACLTokenEntryAndEntity(req) + if err != nil { + return nil, err + } + if entity != nil && entity.Disabled { + b.logger.Warn("permission denied as the entity on the token is disabled") + return errResp, logical.ErrPermissionDenied + } + if te != nil && te.EntityID != "" && entity == nil { + b.logger.Warn("permission denied as the entity on the token is invalid") + return nil, 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, te, entity, _, err := b.Core.fetchACLTokenEntryAndEntity(req) + if err != nil { + return nil, err + } + + if entity != nil && entity.Disabled { + b.logger.Warn("permission denied as the entity on the token is disabled") + return logical.ErrorResponse(logical.ErrPermissionDenied.Error()), nil + } + if te != nil && te.EntityID != "" && entity == nil { + b.logger.Warn("permission denied as the entity on the token is invalid") + 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 000000000..d9fdb046b --- /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 000000000..7a2c70b90 --- /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 000000000..633b7c341 --- /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 000000000..e130df8ba --- /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 000000000..c74d9f3c8 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/policy.go @@ -0,0 +1,308 @@ +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/hclutil" + "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 := hclutil.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 := hclutil.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 +} 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 000000000..bb2bd5dac --- /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 000000000..a55f184f9 --- /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 000000000..3cbd22f33 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/request_forwarding.go @@ -0,0 +1,516 @@ +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{ + // Our forwarding connections heartbeat regularly so anything else we + // want to go away/get cleaned up pretty rapidly + IdleTimeout: 5 * HeartbeatInterval, + } + + // Shutdown coordination logic + shutdown := new(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) + + // Set a deadline for the handshake. This will cause clients + // that don't successfully auth to be kicked out quickly. + // Cluster connections should be reliable so being marginally + // aggressive here is fine. + err = tlsConn.SetDeadline(time.Now().Add(30 * time.Second)) + if err != nil { + if c.logger.IsDebug() { + c.logger.Debug("error setting deadline for cluster connection", "error", err) + } + tlsConn.Close() + continue + } + + err = tlsConn.Handshake() + if err != nil { + if c.logger.IsDebug() { + c.logger.Debug("error handshaking cluster connection", "error", err) + } + tlsConn.Close() + continue + } + + // Now, set it back to unlimited + err = tlsConn.SetDeadline(time.Time{}) + if err != nil { + if c.logger.IsDebug() { + c.logger.Debug("error setting deadline for 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 000000000..cfe102478 --- /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 000000000..ba32f7dfb --- /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 000000000..fd91e33db --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/request_handling.go @@ -0,0 +1,868 @@ +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, *logical.TokenEntry, *identity.Entity, []string, 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, nil, fmt.Errorf("missing client token") + } + + if c.tokenStore == nil { + c.logger.Error("token store is unavailable") + return nil, nil, nil, nil, ErrInternalError + } + + // Resolve the token policy + var te *logical.TokenEntry + switch req.TokenEntry() { + case nil: + var err error + 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, nil, ErrInternalError + } + default: + te = req.TokenEntry() + } + + // Ensure the token is valid + if te == nil { + return nil, 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, nil, logical.ErrPermissionDenied + } + for _, cidr := range te.BoundCIDRs { + if cidr.Contains(remoteSockAddr) { + valid = true + break + } + } + if !valid { + return nil, nil, nil, nil, logical.ErrPermissionDenied + } + } + + entity, identityPolicies, err := c.fetchEntityAndDerivedPolicies(te.EntityID) + if err != nil { + return nil, nil, nil, nil, ErrInternalError + } + + allPolicies := append(te.Policies, identityPolicies...) + + // Construct the corresponding ACL object + acl, err := c.policyStore.ACL(c.activeContext, allPolicies...) + if err != nil { + c.logger.Error("failed to construct ACL", "error", err) + return nil, nil, nil, nil, ErrInternalError + } + + return acl, te, entity, identityPolicies, nil +} + +func (c *Core) checkToken(ctx context.Context, req *logical.Request, unauth bool) (*logical.Auth, *logical.TokenEntry, error) { + defer metrics.MeasureSince([]string{"core", "check_token"}, time.Now()) + + var acl *ACL + var te *logical.TokenEntry + var entity *identity.Entity + var identityPolicies []string + 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, identityPolicies, 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 { + c.logger.Warn("permission denied as the entity on the token is disabled") + return nil, te, logical.ErrPermissionDenied + } + if te != nil && te.EntityID != "" && entity == nil { + c.logger.Warn("permission denied as the entity on the token is invalid") + 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, + Policies: identityPolicies, + IdentityPolicies: identityPolicies, + } + + if te != nil { + auth.TokenPolicies = te.Policies + auth.Policies = append(te.Policies, identityPolicies...) + 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 + } + + _, identityPolicies, err := c.fetchEntityAndDerivedPolicies(resp.Auth.EntityID) + if err != nil { + c.tokenStore.revokeOrphan(ctx, te.ID) + return nil, nil, ErrInternalError + } + + resp.Auth.TokenPolicies = policyutil.SanitizePolicies(resp.Auth.Policies, policyutil.DoNotAddDefaultPolicy) + resp.Auth.IdentityPolicies = policyutil.SanitizePolicies(identityPolicies, policyutil.DoNotAddDefaultPolicy) + resp.Auth.Policies = policyutil.SanitizePolicies(append(resp.Auth.Policies, identityPolicies...), policyutil.DoNotAddDefaultPolicy) + + 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 + } + } + } + + // 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) + } + + // We first assign token policies to what was returned from the backend + // via auth.Policies. Then, we get the full set of policies into + // auth.Policies from the backend + entity information -- this is not + // stored in the token, but we perform sanity checks on it and return + // that information to the user. + + // Generate a token + te := logical.TokenEntry{ + Path: req.Path, + 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(auth.Policies, policyutil.AddDefaultPolicy) + + _, identityPolicies, err := c.fetchEntityAndDerivedPolicies(auth.EntityID) + if err != nil { + return nil, nil, ErrInternalError + } + + auth.TokenPolicies = te.Policies + auth.IdentityPolicies = policyutil.SanitizePolicies(identityPolicies, policyutil.DoNotAddDefaultPolicy) + auth.Policies = policyutil.SanitizePolicies(append(te.Policies, identityPolicies...), policyutil.DoNotAddDefaultPolicy) + + // Prevent internal policies from being assigned to tokens. We check + // this on auth.Policies including derived ones from Identity before + // actually making the token. + for _, policy := range auth.Policies { + if policy == "root" { + return logical.ErrorResponse("auth methods cannot create root tokens"), nil, logical.ErrInvalidRequest + } + 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.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 000000000..995424631 --- /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 000000000..cced9b579 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/router.go @@ -0,0 +1,655 @@ +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() + + _, raw, ok := r.mountUUIDCache.LongestPrefix(mountID) + if !ok { + r.l.RUnlock() + return nil + } + + r.l.RUnlock() + return raw.(*MountEntry) +} + +// MatchingMountByAccessor returns the MountEntry by accessor lookup +func (r *Router) MatchingMountByAccessor(mountAccessor string) *MountEntry { + if mountAccessor == "" { + return nil + } + + r.l.RLock() + + _, raw, ok := r.mountAccessorCache.LongestPrefix(mountAccessor) + if !ok { + r.l.RUnlock() + return nil + } + + r.l.RUnlock() + 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() + mount := r.matchingMountInternal(path) + r.l.RUnlock() + 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, + } + } + + reqTokenEntry := req.TokenEntry() + req.SetTokenEntry(nil) + + // 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 + + req.SetTokenEntry(reqTokenEntry) + }() + + // 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 000000000..fc6790ff6 --- /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 000000000..363a47daf --- /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 000000000..5c44bd184 --- /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 000000000..a3d4abf19 --- /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 000000000..a7e6fc222 --- /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 000000000..da8985e81 --- /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 000000000..9526c72c0 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/vault/token_store.go @@ -0,0 +1,2616 @@ +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) (*logical.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 *uint32 + + 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, + tidyLock: new(uint32), + } + + 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 +} + +// 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) (*logical.TokenEntry, error) { + te := &logical.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 *logical.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 *logical.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 *logical.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 *logical.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 *logical.TokenEntry) (*logical.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) (*logical.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) (*logical.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) (*logical.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) (*logical.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(logical.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 + } + + // 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. Fast-path this. + if len(entry.Policies) == 1 && entry.Policies[0] == "root" && entry.TTL == 0 { + // 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 entry, nil + } + + // 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 *logical.TokenEntry + + switch { + // 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) { + if !atomic.CompareAndSwapUint32(ts.tidyLock, 0, 1) { + resp := &logical.Response{} + resp.AddWarning("Tidy operation already in progress.") + return resp, nil + } + + go func() { + defer atomic.StoreUint32(ts.tidyLock, 0) + + // Don't cancel when the original client request goes away + ctx = context.Background() + + logger := ts.logger.Named("tidy") + + var tidyErrors *multierror.Error + + doTidy := func() error { + + 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 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 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 '*logical.TokenEntry'. For the + // purposes of tidying, it is sufficient if the token + // entry only has ID set. + tokenEntry := &logical.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 tidyErrors.ErrorOrNil() + } + + if err := doTidy(); err != nil { + logger.Error("error running tidy", "error", err) + return + } + }() + + resp := &logical.Response{} + resp.AddWarning("Tidy operation successfully started. Any information from the operation will be printed to Vault's server logs.") + return resp, nil +} + +// 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 := logical.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 (%q) must be subset of the role's allowed policies (%q)", 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 000000000..7a637f20a --- /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 000000000..9e03afd29 --- /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 000000000..5f2b59d5c --- /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 := logical.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 000000000..2ed493a1f --- /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 000000000..0f8193335 --- /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 000000000..c9f323bbc --- /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.3" + + // 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/jefferai/jsonx/LICENSE b/vendor/github.com/jefferai/jsonx/LICENSE new file mode 100644 index 000000000..a612ad981 --- /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 000000000..a7bb5bac9 --- /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 000000000..93d24a9b0 --- /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/keybase/go-crypto/LICENSE b/vendor/github.com/keybase/go-crypto/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 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/keybase/go-crypto/PATENTS b/vendor/github.com/keybase/go-crypto/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/keybase/go-crypto/brainpool/brainpool.go b/vendor/github.com/keybase/go-crypto/brainpool/brainpool.go new file mode 100644 index 000000000..77fb8b9a0 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/brainpool/brainpool.go @@ -0,0 +1,134 @@ +// Package brainpool implements Brainpool elliptic curves. +// Implementation of rcurves is from github.com/ebfe/brainpool +// Note that these curves are implemented with naive, non-constant time operations +// and are likely not suitable for enviroments where timing attacks are a concern. +package brainpool + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +var ( + once sync.Once + p256t1, p384t1, p512t1 *elliptic.CurveParams + p256r1, p384r1, p512r1 *rcurve +) + +func initAll() { + initP256t1() + initP384t1() + initP512t1() + initP256r1() + initP384r1() + initP512r1() +} + +func initP256t1() { + p256t1 = &elliptic.CurveParams{Name: "brainpoolP256t1"} + p256t1.P, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16) + p256t1.N, _ = new(big.Int).SetString("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16) + p256t1.B, _ = new(big.Int).SetString("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16) + p256t1.Gx, _ = new(big.Int).SetString("A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4", 16) + p256t1.Gy, _ = new(big.Int).SetString("2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE", 16) + p256t1.BitSize = 256 +} + +func initP256r1() { + twisted := p256t1 + params := &elliptic.CurveParams{ + Name: "brainpoolP256r1", + P: twisted.P, + N: twisted.N, + BitSize: twisted.BitSize, + } + params.Gx, _ = new(big.Int).SetString("8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", 16) + params.Gy, _ = new(big.Int).SetString("547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", 16) + z, _ := new(big.Int).SetString("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0", 16) + p256r1 = newrcurve(twisted, params, z) +} + +func initP384t1() { + p384t1 = &elliptic.CurveParams{Name: "brainpoolP384t1"} + p384t1.P, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16) + p384t1.N, _ = new(big.Int).SetString("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16) + p384t1.B, _ = new(big.Int).SetString("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16) + p384t1.Gx, _ = new(big.Int).SetString("18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC", 16) + p384t1.Gy, _ = new(big.Int).SetString("25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928", 16) + p384t1.BitSize = 384 +} + +func initP384r1() { + twisted := p384t1 + params := &elliptic.CurveParams{ + Name: "brainpoolP384r1", + P: twisted.P, + N: twisted.N, + BitSize: twisted.BitSize, + } + params.Gx, _ = new(big.Int).SetString("1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", 16) + params.Gy, _ = new(big.Int).SetString("8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", 16) + z, _ := new(big.Int).SetString("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C", 16) + p384r1 = newrcurve(twisted, params, z) +} + +func initP512t1() { + p512t1 = &elliptic.CurveParams{Name: "brainpoolP512t1"} + p512t1.P, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16) + p512t1.N, _ = new(big.Int).SetString("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16) + p512t1.B, _ = new(big.Int).SetString("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16) + p512t1.Gx, _ = new(big.Int).SetString("640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA", 16) + p512t1.Gy, _ = new(big.Int).SetString("5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332", 16) + p512t1.BitSize = 512 +} + +func initP512r1() { + twisted := p512t1 + params := &elliptic.CurveParams{ + Name: "brainpoolP512r1", + P: twisted.P, + N: twisted.N, + BitSize: twisted.BitSize, + } + params.Gx, _ = new(big.Int).SetString("81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", 16) + params.Gy, _ = new(big.Int).SetString("7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", 16) + z, _ := new(big.Int).SetString("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB", 16) + p512r1 = newrcurve(twisted, params, z) +} + +// P256t1 returns a Curve which implements Brainpool P256t1 (see RFC 5639, section 3.4) +func P256t1() elliptic.Curve { + once.Do(initAll) + return p256t1 +} + +// P256r1 returns a Curve which implements Brainpool P256r1 (see RFC 5639, section 3.4) +func P256r1() elliptic.Curve { + once.Do(initAll) + return p256r1 +} + +// P384t1 returns a Curve which implements Brainpool P384t1 (see RFC 5639, section 3.6) +func P384t1() elliptic.Curve { + once.Do(initAll) + return p384t1 +} + +// P384r1 returns a Curve which implements Brainpool P384r1 (see RFC 5639, section 3.6) +func P384r1() elliptic.Curve { + once.Do(initAll) + return p384r1 +} + +// P512t1 returns a Curve which implements Brainpool P512t1 (see RFC 5639, section 3.7) +func P512t1() elliptic.Curve { + once.Do(initAll) + return p512t1 +} + +// P512r1 returns a Curve which implements Brainpool P512r1 (see RFC 5639, section 3.7) +func P512r1() elliptic.Curve { + once.Do(initAll) + return p512r1 +} diff --git a/vendor/github.com/keybase/go-crypto/brainpool/rcurve.go b/vendor/github.com/keybase/go-crypto/brainpool/rcurve.go new file mode 100644 index 000000000..7e291d6aa --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/brainpool/rcurve.go @@ -0,0 +1,83 @@ +package brainpool + +import ( + "crypto/elliptic" + "math/big" +) + +var _ elliptic.Curve = (*rcurve)(nil) + +type rcurve struct { + twisted elliptic.Curve + params *elliptic.CurveParams + z *big.Int + zinv *big.Int + z2 *big.Int + z3 *big.Int + zinv2 *big.Int + zinv3 *big.Int +} + +var ( + two = big.NewInt(2) + three = big.NewInt(3) +) + +func newrcurve(twisted elliptic.Curve, params *elliptic.CurveParams, z *big.Int) *rcurve { + zinv := new(big.Int).ModInverse(z, params.P) + return &rcurve{ + twisted: twisted, + params: params, + z: z, + zinv: zinv, + z2: new(big.Int).Exp(z, two, params.P), + z3: new(big.Int).Exp(z, three, params.P), + zinv2: new(big.Int).Exp(zinv, two, params.P), + zinv3: new(big.Int).Exp(zinv, three, params.P), + } +} + +func (curve *rcurve) toTwisted(x, y *big.Int) (*big.Int, *big.Int) { + var tx, ty big.Int + tx.Mul(x, curve.z2) + tx.Mod(&tx, curve.params.P) + ty.Mul(y, curve.z3) + ty.Mod(&ty, curve.params.P) + return &tx, &ty +} + +func (curve *rcurve) fromTwisted(tx, ty *big.Int) (*big.Int, *big.Int) { + var x, y big.Int + x.Mul(tx, curve.zinv2) + x.Mod(&x, curve.params.P) + y.Mul(ty, curve.zinv3) + y.Mod(&y, curve.params.P) + return &x, &y +} + +func (curve *rcurve) Params() *elliptic.CurveParams { + return curve.params +} + +func (curve *rcurve) IsOnCurve(x, y *big.Int) bool { + return curve.twisted.IsOnCurve(curve.toTwisted(x, y)) +} + +func (curve *rcurve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) { + tx1, ty1 := curve.toTwisted(x1, y1) + tx2, ty2 := curve.toTwisted(x2, y2) + return curve.fromTwisted(curve.twisted.Add(tx1, ty1, tx2, ty2)) +} + +func (curve *rcurve) Double(x1, y1 *big.Int) (x, y *big.Int) { + return curve.fromTwisted(curve.twisted.Double(curve.toTwisted(x1, y1))) +} + +func (curve *rcurve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { + tx1, ty1 := curve.toTwisted(x1, y1) + return curve.fromTwisted(curve.twisted.ScalarMult(tx1, ty1, scalar)) +} + +func (curve *rcurve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { + return curve.fromTwisted(curve.twisted.ScalarBaseMult(scalar)) +} diff --git a/vendor/github.com/keybase/go-crypto/cast5/cast5.go b/vendor/github.com/keybase/go-crypto/cast5/cast5.go new file mode 100644 index 000000000..8c1b299bf --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/cast5/cast5.go @@ -0,0 +1,526 @@ +// Copyright 2010 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 cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common +// OpenPGP cipher. +package cast5 + +import "errors" + +const BlockSize = 8 +const KeySize = 16 + +type Cipher struct { + masking [16]uint32 + rotate [16]uint8 +} + +func NewCipher(key []byte) (c *Cipher, err error) { + if len(key) != KeySize { + return nil, errors.New("CAST5: keys must be 16 bytes") + } + + c = new(Cipher) + c.keySchedule(key) + return +} + +func (c *Cipher) BlockSize() int { + return BlockSize +} + +func (c *Cipher) Encrypt(dst, src []byte) { + l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + + l, r = r, l^f1(r, c.masking[0], c.rotate[0]) + l, r = r, l^f2(r, c.masking[1], c.rotate[1]) + l, r = r, l^f3(r, c.masking[2], c.rotate[2]) + l, r = r, l^f1(r, c.masking[3], c.rotate[3]) + + l, r = r, l^f2(r, c.masking[4], c.rotate[4]) + l, r = r, l^f3(r, c.masking[5], c.rotate[5]) + l, r = r, l^f1(r, c.masking[6], c.rotate[6]) + l, r = r, l^f2(r, c.masking[7], c.rotate[7]) + + l, r = r, l^f3(r, c.masking[8], c.rotate[8]) + l, r = r, l^f1(r, c.masking[9], c.rotate[9]) + l, r = r, l^f2(r, c.masking[10], c.rotate[10]) + l, r = r, l^f3(r, c.masking[11], c.rotate[11]) + + l, r = r, l^f1(r, c.masking[12], c.rotate[12]) + l, r = r, l^f2(r, c.masking[13], c.rotate[13]) + l, r = r, l^f3(r, c.masking[14], c.rotate[14]) + l, r = r, l^f1(r, c.masking[15], c.rotate[15]) + + dst[0] = uint8(r >> 24) + dst[1] = uint8(r >> 16) + dst[2] = uint8(r >> 8) + dst[3] = uint8(r) + dst[4] = uint8(l >> 24) + dst[5] = uint8(l >> 16) + dst[6] = uint8(l >> 8) + dst[7] = uint8(l) +} + +func (c *Cipher) Decrypt(dst, src []byte) { + l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + + l, r = r, l^f1(r, c.masking[15], c.rotate[15]) + l, r = r, l^f3(r, c.masking[14], c.rotate[14]) + l, r = r, l^f2(r, c.masking[13], c.rotate[13]) + l, r = r, l^f1(r, c.masking[12], c.rotate[12]) + + l, r = r, l^f3(r, c.masking[11], c.rotate[11]) + l, r = r, l^f2(r, c.masking[10], c.rotate[10]) + l, r = r, l^f1(r, c.masking[9], c.rotate[9]) + l, r = r, l^f3(r, c.masking[8], c.rotate[8]) + + l, r = r, l^f2(r, c.masking[7], c.rotate[7]) + l, r = r, l^f1(r, c.masking[6], c.rotate[6]) + l, r = r, l^f3(r, c.masking[5], c.rotate[5]) + l, r = r, l^f2(r, c.masking[4], c.rotate[4]) + + l, r = r, l^f1(r, c.masking[3], c.rotate[3]) + l, r = r, l^f3(r, c.masking[2], c.rotate[2]) + l, r = r, l^f2(r, c.masking[1], c.rotate[1]) + l, r = r, l^f1(r, c.masking[0], c.rotate[0]) + + dst[0] = uint8(r >> 24) + dst[1] = uint8(r >> 16) + dst[2] = uint8(r >> 8) + dst[3] = uint8(r) + dst[4] = uint8(l >> 24) + dst[5] = uint8(l >> 16) + dst[6] = uint8(l >> 8) + dst[7] = uint8(l) +} + +type keyScheduleA [4][7]uint8 +type keyScheduleB [4][5]uint8 + +// keyScheduleRound contains the magic values for a round of the key schedule. +// The keyScheduleA deals with the lines like: +// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8] +// Conceptually, both x and z are in the same array, x first. The first +// element describes which word of this array gets written to and the +// second, which word gets read. So, for the line above, it's "4, 0", because +// it's writing to the first word of z, which, being after x, is word 4, and +// reading from the first word of x: word 0. +// +// Next are the indexes into the S-boxes. Now the array is treated as bytes. So +// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear +// that it's z that we're indexing. +// +// keyScheduleB deals with lines like: +// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2] +// "K1" is ignored because key words are always written in order. So the five +// elements are the S-box indexes. They use the same form as in keyScheduleA, +// above. + +type keyScheduleRound struct{} +type keySchedule []keyScheduleRound + +var schedule = []struct { + a keyScheduleA + b keyScheduleB +}{ + { + keyScheduleA{ + {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8}, + {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa}, + {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9}, + {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb}, + }, + keyScheduleB{ + {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2}, + {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6}, + {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9}, + {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc}, + }, + }, + { + keyScheduleA{ + {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0}, + {1, 4, 0, 2, 1, 3, 16 + 2}, + {2, 5, 7, 6, 5, 4, 16 + 1}, + {3, 7, 0xa, 9, 0xb, 8, 16 + 3}, + }, + keyScheduleB{ + {3, 2, 0xc, 0xd, 8}, + {1, 0, 0xe, 0xf, 0xd}, + {7, 6, 8, 9, 3}, + {5, 4, 0xa, 0xb, 7}, + }, + }, + { + keyScheduleA{ + {4, 0, 0xd, 0xf, 0xc, 0xe, 8}, + {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa}, + {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9}, + {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb}, + }, + keyScheduleB{ + {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9}, + {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc}, + {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2}, + {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6}, + }, + }, + { + keyScheduleA{ + {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0}, + {1, 4, 0, 2, 1, 3, 16 + 2}, + {2, 5, 7, 6, 5, 4, 16 + 1}, + {3, 7, 0xa, 9, 0xb, 8, 16 + 3}, + }, + keyScheduleB{ + {8, 9, 7, 6, 3}, + {0xa, 0xb, 5, 4, 7}, + {0xc, 0xd, 3, 2, 8}, + {0xe, 0xf, 1, 0, 0xd}, + }, + }, +} + +func (c *Cipher) keySchedule(in []byte) { + var t [8]uint32 + var k [32]uint32 + + for i := 0; i < 4; i++ { + j := i * 4 + t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3]) + } + + x := []byte{6, 7, 4, 5} + ki := 0 + + for half := 0; half < 2; half++ { + for _, round := range schedule { + for j := 0; j < 4; j++ { + var a [7]uint8 + copy(a[:], round.a[j][:]) + w := t[a[1]] + w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff] + w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff] + w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff] + w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff] + w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff] + t[a[0]] = w + } + + for j := 0; j < 4; j++ { + var b [5]uint8 + copy(b[:], round.b[j][:]) + w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff] + w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff] + w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff] + w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff] + w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff] + k[ki] = w + ki++ + } + } + } + + for i := 0; i < 16; i++ { + c.masking[i] = k[i] + c.rotate[i] = uint8(k[16+i] & 0x1f) + } +} + +// These are the three 'f' functions. See RFC 2144, section 2.2. +func f1(d, m uint32, r uint8) uint32 { + t := m + d + I := (t << r) | (t >> (32 - r)) + return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff] +} + +func f2(d, m uint32, r uint8) uint32 { + t := m ^ d + I := (t << r) | (t >> (32 - r)) + return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff] +} + +func f3(d, m uint32, r uint8) uint32 { + t := m - d + I := (t << r) | (t >> (32 - r)) + return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff] +} + +var sBox = [8][256]uint32{ + { + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf, + }, + { + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1, + }, + { + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783, + }, + { + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2, + }, + { + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4, + }, + { + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f, + }, + { + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3, + }, + { + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e, + }, +} diff --git a/vendor/github.com/keybase/go-crypto/curve25519/const_amd64.s b/vendor/github.com/keybase/go-crypto/curve25519/const_amd64.s new file mode 100644 index 000000000..797f9b051 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/const_amd64.s @@ -0,0 +1,20 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF +GLOBL ·REDMASK51(SB), 8, $8 + +DATA ·_121666_213(SB)/8, $996687872 +GLOBL ·_121666_213(SB), 8, $8 + +DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA +GLOBL ·_2P0(SB), 8, $8 + +DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE +GLOBL ·_2P1234(SB), 8, $8 diff --git a/vendor/github.com/keybase/go-crypto/curve25519/cswap_amd64.s b/vendor/github.com/keybase/go-crypto/curve25519/cswap_amd64.s new file mode 100644 index 000000000..45484d1b5 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/cswap_amd64.s @@ -0,0 +1,88 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func cswap(inout *[5]uint64, v uint64) +TEXT ·cswap(SB),7,$0 + MOVQ inout+0(FP),DI + MOVQ v+8(FP),SI + + CMPQ SI,$1 + MOVQ 0(DI),SI + MOVQ 80(DI),DX + MOVQ 8(DI),CX + MOVQ 88(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,0(DI) + MOVQ DX,80(DI) + MOVQ CX,8(DI) + MOVQ R8,88(DI) + MOVQ 16(DI),SI + MOVQ 96(DI),DX + MOVQ 24(DI),CX + MOVQ 104(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,16(DI) + MOVQ DX,96(DI) + MOVQ CX,24(DI) + MOVQ R8,104(DI) + MOVQ 32(DI),SI + MOVQ 112(DI),DX + MOVQ 40(DI),CX + MOVQ 120(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,32(DI) + MOVQ DX,112(DI) + MOVQ CX,40(DI) + MOVQ R8,120(DI) + MOVQ 48(DI),SI + MOVQ 128(DI),DX + MOVQ 56(DI),CX + MOVQ 136(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,48(DI) + MOVQ DX,128(DI) + MOVQ CX,56(DI) + MOVQ R8,136(DI) + MOVQ 64(DI),SI + MOVQ 144(DI),DX + MOVQ 72(DI),CX + MOVQ 152(DI),R8 + MOVQ SI,R9 + CMOVQEQ DX,SI + CMOVQEQ R9,DX + MOVQ CX,R9 + CMOVQEQ R8,CX + CMOVQEQ R9,R8 + MOVQ SI,64(DI) + MOVQ DX,144(DI) + MOVQ CX,72(DI) + MOVQ R8,152(DI) + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/keybase/go-crypto/curve25519/curve25519.go b/vendor/github.com/keybase/go-crypto/curve25519/curve25519.go new file mode 100644 index 000000000..6918c47fc --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/curve25519.go @@ -0,0 +1,841 @@ +// 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. + +// We have a implementation in amd64 assembly so this code is only run on +// non-amd64 platforms. The amd64 assembly does not support gccgo. +// +build !amd64 gccgo appengine + +package curve25519 + +// This code is a port of the public domain, "ref10" implementation of +// curve25519 from SUPERCOP 20130419 by D. J. Bernstein. + +// fieldElement represents an element of the field GF(2^255 - 19). An element +// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 +// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on +// context. +type fieldElement [10]int32 + +func feZero(fe *fieldElement) { + for i := range fe { + fe[i] = 0 + } +} + +func feOne(fe *fieldElement) { + feZero(fe) + fe[0] = 1 +} + +func feAdd(dst, a, b *fieldElement) { + for i := range dst { + dst[i] = a[i] + b[i] + } +} + +func feSub(dst, a, b *fieldElement) { + for i := range dst { + dst[i] = a[i] - b[i] + } +} + +func feCopy(dst, src *fieldElement) { + for i := range dst { + dst[i] = src[i] + } +} + +// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0. +// +// Preconditions: b in {0,1}. +func feCSwap(f, g *fieldElement, b int32) { + var x fieldElement + b = -b + for i := range x { + x[i] = b & (f[i] ^ g[i]) + } + + for i := range f { + f[i] ^= x[i] + } + for i := range g { + g[i] ^= x[i] + } +} + +// load3 reads a 24-bit, little-endian value from in. +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +// load4 reads a 32-bit, little-endian value from in. +func load4(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +func feFromBytes(dst *fieldElement, src *[32]byte) { + h0 := load4(src[:]) + h1 := load3(src[4:]) << 6 + h2 := load3(src[7:]) << 5 + h3 := load3(src[10:]) << 3 + h4 := load3(src[13:]) << 2 + h5 := load4(src[16:]) + h6 := load3(src[20:]) << 7 + h7 := load3(src[23:]) << 5 + h8 := load3(src[26:]) << 4 + h9 := load3(src[29:]) << 2 + + var carry [10]int64 + carry[9] = (h9 + 1<<24) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + carry[1] = (h1 + 1<<24) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[3] = (h3 + 1<<24) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[5] = (h5 + 1<<24) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + carry[7] = (h7 + 1<<24) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[0] = (h0 + 1<<25) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[2] = (h2 + 1<<25) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[4] = (h4 + 1<<25) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[6] = (h6 + 1<<25) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + carry[8] = (h8 + 1<<25) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + dst[0] = int32(h0) + dst[1] = int32(h1) + dst[2] = int32(h2) + dst[3] = int32(h3) + dst[4] = int32(h4) + dst[5] = int32(h5) + dst[6] = int32(h6) + dst[7] = int32(h7) + dst[8] = int32(h8) + dst[9] = int32(h9) +} + +// feToBytes marshals h to s. +// Preconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Write p=2^255-19; q=floor(h/p). +// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). +// +// Proof: +// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. +// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. +// +// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). +// Then 0> 25 + q = (h[0] + q) >> 26 + q = (h[1] + q) >> 25 + q = (h[2] + q) >> 26 + q = (h[3] + q) >> 25 + q = (h[4] + q) >> 26 + q = (h[5] + q) >> 25 + q = (h[6] + q) >> 26 + q = (h[7] + q) >> 25 + q = (h[8] + q) >> 26 + q = (h[9] + q) >> 25 + + // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. + h[0] += 19 * q + // Goal: Output h-2^255 q, which is between 0 and 2^255-20. + + carry[0] = h[0] >> 26 + h[1] += carry[0] + h[0] -= carry[0] << 26 + carry[1] = h[1] >> 25 + h[2] += carry[1] + h[1] -= carry[1] << 25 + carry[2] = h[2] >> 26 + h[3] += carry[2] + h[2] -= carry[2] << 26 + carry[3] = h[3] >> 25 + h[4] += carry[3] + h[3] -= carry[3] << 25 + carry[4] = h[4] >> 26 + h[5] += carry[4] + h[4] -= carry[4] << 26 + carry[5] = h[5] >> 25 + h[6] += carry[5] + h[5] -= carry[5] << 25 + carry[6] = h[6] >> 26 + h[7] += carry[6] + h[6] -= carry[6] << 26 + carry[7] = h[7] >> 25 + h[8] += carry[7] + h[7] -= carry[7] << 25 + carry[8] = h[8] >> 26 + h[9] += carry[8] + h[8] -= carry[8] << 26 + carry[9] = h[9] >> 25 + h[9] -= carry[9] << 25 + // h10 = carry9 + + // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; + // evidently 2^255 h10-2^255 q = 0. + // Goal: Output h[0]+...+2^230 h[9]. + + s[0] = byte(h[0] >> 0) + s[1] = byte(h[0] >> 8) + s[2] = byte(h[0] >> 16) + s[3] = byte((h[0] >> 24) | (h[1] << 2)) + s[4] = byte(h[1] >> 6) + s[5] = byte(h[1] >> 14) + s[6] = byte((h[1] >> 22) | (h[2] << 3)) + s[7] = byte(h[2] >> 5) + s[8] = byte(h[2] >> 13) + s[9] = byte((h[2] >> 21) | (h[3] << 5)) + s[10] = byte(h[3] >> 3) + s[11] = byte(h[3] >> 11) + s[12] = byte((h[3] >> 19) | (h[4] << 6)) + s[13] = byte(h[4] >> 2) + s[14] = byte(h[4] >> 10) + s[15] = byte(h[4] >> 18) + s[16] = byte(h[5] >> 0) + s[17] = byte(h[5] >> 8) + s[18] = byte(h[5] >> 16) + s[19] = byte((h[5] >> 24) | (h[6] << 1)) + s[20] = byte(h[6] >> 7) + s[21] = byte(h[6] >> 15) + s[22] = byte((h[6] >> 23) | (h[7] << 3)) + s[23] = byte(h[7] >> 5) + s[24] = byte(h[7] >> 13) + s[25] = byte((h[7] >> 21) | (h[8] << 4)) + s[26] = byte(h[8] >> 4) + s[27] = byte(h[8] >> 12) + s[28] = byte((h[8] >> 20) | (h[9] << 6)) + s[29] = byte(h[9] >> 2) + s[30] = byte(h[9] >> 10) + s[31] = byte(h[9] >> 18) +} + +// feMul calculates h = f * g +// Can overlap h with f or g. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Notes on implementation strategy: +// +// Using schoolbook multiplication. +// Karatsuba would save a little in some cost models. +// +// Most multiplications by 2 and 19 are 32-bit precomputations; +// cheaper than 64-bit postcomputations. +// +// There is one remaining multiplication by 19 in the carry chain; +// one *19 precomputation can be merged into this, +// but the resulting data flow is considerably less clean. +// +// There are 12 carries below. +// 10 of them are 2-way parallelizable and vectorizable. +// Can get away with 11 carries, but then data flow is much deeper. +// +// With tighter constraints on inputs can squeeze carries into int32. +func feMul(h, f, g *fieldElement) { + f0 := f[0] + f1 := f[1] + f2 := f[2] + f3 := f[3] + f4 := f[4] + f5 := f[5] + f6 := f[6] + f7 := f[7] + f8 := f[8] + f9 := f[9] + g0 := g[0] + g1 := g[1] + g2 := g[2] + g3 := g[3] + g4 := g[4] + g5 := g[5] + g6 := g[6] + g7 := g[7] + g8 := g[8] + g9 := g[9] + g1_19 := 19 * g1 // 1.4*2^29 + g2_19 := 19 * g2 // 1.4*2^30; still ok + g3_19 := 19 * g3 + g4_19 := 19 * g4 + g5_19 := 19 * g5 + g6_19 := 19 * g6 + g7_19 := 19 * g7 + g8_19 := 19 * g8 + g9_19 := 19 * g9 + f1_2 := 2 * f1 + f3_2 := 2 * f3 + f5_2 := 2 * f5 + f7_2 := 2 * f7 + f9_2 := 2 * f9 + f0g0 := int64(f0) * int64(g0) + f0g1 := int64(f0) * int64(g1) + f0g2 := int64(f0) * int64(g2) + f0g3 := int64(f0) * int64(g3) + f0g4 := int64(f0) * int64(g4) + f0g5 := int64(f0) * int64(g5) + f0g6 := int64(f0) * int64(g6) + f0g7 := int64(f0) * int64(g7) + f0g8 := int64(f0) * int64(g8) + f0g9 := int64(f0) * int64(g9) + f1g0 := int64(f1) * int64(g0) + f1g1_2 := int64(f1_2) * int64(g1) + f1g2 := int64(f1) * int64(g2) + f1g3_2 := int64(f1_2) * int64(g3) + f1g4 := int64(f1) * int64(g4) + f1g5_2 := int64(f1_2) * int64(g5) + f1g6 := int64(f1) * int64(g6) + f1g7_2 := int64(f1_2) * int64(g7) + f1g8 := int64(f1) * int64(g8) + f1g9_38 := int64(f1_2) * int64(g9_19) + f2g0 := int64(f2) * int64(g0) + f2g1 := int64(f2) * int64(g1) + f2g2 := int64(f2) * int64(g2) + f2g3 := int64(f2) * int64(g3) + f2g4 := int64(f2) * int64(g4) + f2g5 := int64(f2) * int64(g5) + f2g6 := int64(f2) * int64(g6) + f2g7 := int64(f2) * int64(g7) + f2g8_19 := int64(f2) * int64(g8_19) + f2g9_19 := int64(f2) * int64(g9_19) + f3g0 := int64(f3) * int64(g0) + f3g1_2 := int64(f3_2) * int64(g1) + f3g2 := int64(f3) * int64(g2) + f3g3_2 := int64(f3_2) * int64(g3) + f3g4 := int64(f3) * int64(g4) + f3g5_2 := int64(f3_2) * int64(g5) + f3g6 := int64(f3) * int64(g6) + f3g7_38 := int64(f3_2) * int64(g7_19) + f3g8_19 := int64(f3) * int64(g8_19) + f3g9_38 := int64(f3_2) * int64(g9_19) + f4g0 := int64(f4) * int64(g0) + f4g1 := int64(f4) * int64(g1) + f4g2 := int64(f4) * int64(g2) + f4g3 := int64(f4) * int64(g3) + f4g4 := int64(f4) * int64(g4) + f4g5 := int64(f4) * int64(g5) + f4g6_19 := int64(f4) * int64(g6_19) + f4g7_19 := int64(f4) * int64(g7_19) + f4g8_19 := int64(f4) * int64(g8_19) + f4g9_19 := int64(f4) * int64(g9_19) + f5g0 := int64(f5) * int64(g0) + f5g1_2 := int64(f5_2) * int64(g1) + f5g2 := int64(f5) * int64(g2) + f5g3_2 := int64(f5_2) * int64(g3) + f5g4 := int64(f5) * int64(g4) + f5g5_38 := int64(f5_2) * int64(g5_19) + f5g6_19 := int64(f5) * int64(g6_19) + f5g7_38 := int64(f5_2) * int64(g7_19) + f5g8_19 := int64(f5) * int64(g8_19) + f5g9_38 := int64(f5_2) * int64(g9_19) + f6g0 := int64(f6) * int64(g0) + f6g1 := int64(f6) * int64(g1) + f6g2 := int64(f6) * int64(g2) + f6g3 := int64(f6) * int64(g3) + f6g4_19 := int64(f6) * int64(g4_19) + f6g5_19 := int64(f6) * int64(g5_19) + f6g6_19 := int64(f6) * int64(g6_19) + f6g7_19 := int64(f6) * int64(g7_19) + f6g8_19 := int64(f6) * int64(g8_19) + f6g9_19 := int64(f6) * int64(g9_19) + f7g0 := int64(f7) * int64(g0) + f7g1_2 := int64(f7_2) * int64(g1) + f7g2 := int64(f7) * int64(g2) + f7g3_38 := int64(f7_2) * int64(g3_19) + f7g4_19 := int64(f7) * int64(g4_19) + f7g5_38 := int64(f7_2) * int64(g5_19) + f7g6_19 := int64(f7) * int64(g6_19) + f7g7_38 := int64(f7_2) * int64(g7_19) + f7g8_19 := int64(f7) * int64(g8_19) + f7g9_38 := int64(f7_2) * int64(g9_19) + f8g0 := int64(f8) * int64(g0) + f8g1 := int64(f8) * int64(g1) + f8g2_19 := int64(f8) * int64(g2_19) + f8g3_19 := int64(f8) * int64(g3_19) + f8g4_19 := int64(f8) * int64(g4_19) + f8g5_19 := int64(f8) * int64(g5_19) + f8g6_19 := int64(f8) * int64(g6_19) + f8g7_19 := int64(f8) * int64(g7_19) + f8g8_19 := int64(f8) * int64(g8_19) + f8g9_19 := int64(f8) * int64(g9_19) + f9g0 := int64(f9) * int64(g0) + f9g1_38 := int64(f9_2) * int64(g1_19) + f9g2_19 := int64(f9) * int64(g2_19) + f9g3_38 := int64(f9_2) * int64(g3_19) + f9g4_19 := int64(f9) * int64(g4_19) + f9g5_38 := int64(f9_2) * int64(g5_19) + f9g6_19 := int64(f9) * int64(g6_19) + f9g7_38 := int64(f9_2) * int64(g7_19) + f9g8_19 := int64(f9) * int64(g8_19) + f9g9_38 := int64(f9_2) * int64(g9_19) + h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 + h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 + h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 + h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 + h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 + h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 + h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 + h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 + h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 + h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 + var carry [10]int64 + + // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) + // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 + // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) + // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + // |h0| <= 2^25 + // |h4| <= 2^25 + // |h1| <= 1.51*2^58 + // |h5| <= 1.51*2^58 + + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + // |h1| <= 2^24; from now on fits into int32 + // |h5| <= 2^24; from now on fits into int32 + // |h2| <= 1.21*2^59 + // |h6| <= 1.21*2^59 + + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + // |h2| <= 2^25; from now on fits into int32 unchanged + // |h6| <= 2^25; from now on fits into int32 unchanged + // |h3| <= 1.51*2^58 + // |h7| <= 1.51*2^58 + + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + // |h3| <= 2^24; from now on fits into int32 unchanged + // |h7| <= 2^24; from now on fits into int32 unchanged + // |h4| <= 1.52*2^33 + // |h8| <= 1.52*2^33 + + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + // |h4| <= 2^25; from now on fits into int32 unchanged + // |h8| <= 2^25; from now on fits into int32 unchanged + // |h5| <= 1.01*2^24 + // |h9| <= 1.51*2^58 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + // |h9| <= 2^24; from now on fits into int32 unchanged + // |h0| <= 1.8*2^37 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + // |h0| <= 2^25; from now on fits into int32 unchanged + // |h1| <= 1.01*2^24 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feSquare calculates h = f*f. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func feSquare(h, f *fieldElement) { + f0 := f[0] + f1 := f[1] + f2 := f[2] + f3 := f[3] + f4 := f[4] + f5 := f[5] + f6 := f[6] + f7 := f[7] + f8 := f[8] + f9 := f[9] + f0_2 := 2 * f0 + f1_2 := 2 * f1 + f2_2 := 2 * f2 + f3_2 := 2 * f3 + f4_2 := 2 * f4 + f5_2 := 2 * f5 + f6_2 := 2 * f6 + f7_2 := 2 * f7 + f5_38 := 38 * f5 // 1.31*2^30 + f6_19 := 19 * f6 // 1.31*2^30 + f7_38 := 38 * f7 // 1.31*2^30 + f8_19 := 19 * f8 // 1.31*2^30 + f9_38 := 38 * f9 // 1.31*2^30 + f0f0 := int64(f0) * int64(f0) + f0f1_2 := int64(f0_2) * int64(f1) + f0f2_2 := int64(f0_2) * int64(f2) + f0f3_2 := int64(f0_2) * int64(f3) + f0f4_2 := int64(f0_2) * int64(f4) + f0f5_2 := int64(f0_2) * int64(f5) + f0f6_2 := int64(f0_2) * int64(f6) + f0f7_2 := int64(f0_2) * int64(f7) + f0f8_2 := int64(f0_2) * int64(f8) + f0f9_2 := int64(f0_2) * int64(f9) + f1f1_2 := int64(f1_2) * int64(f1) + f1f2_2 := int64(f1_2) * int64(f2) + f1f3_4 := int64(f1_2) * int64(f3_2) + f1f4_2 := int64(f1_2) * int64(f4) + f1f5_4 := int64(f1_2) * int64(f5_2) + f1f6_2 := int64(f1_2) * int64(f6) + f1f7_4 := int64(f1_2) * int64(f7_2) + f1f8_2 := int64(f1_2) * int64(f8) + f1f9_76 := int64(f1_2) * int64(f9_38) + f2f2 := int64(f2) * int64(f2) + f2f3_2 := int64(f2_2) * int64(f3) + f2f4_2 := int64(f2_2) * int64(f4) + f2f5_2 := int64(f2_2) * int64(f5) + f2f6_2 := int64(f2_2) * int64(f6) + f2f7_2 := int64(f2_2) * int64(f7) + f2f8_38 := int64(f2_2) * int64(f8_19) + f2f9_38 := int64(f2) * int64(f9_38) + f3f3_2 := int64(f3_2) * int64(f3) + f3f4_2 := int64(f3_2) * int64(f4) + f3f5_4 := int64(f3_2) * int64(f5_2) + f3f6_2 := int64(f3_2) * int64(f6) + f3f7_76 := int64(f3_2) * int64(f7_38) + f3f8_38 := int64(f3_2) * int64(f8_19) + f3f9_76 := int64(f3_2) * int64(f9_38) + f4f4 := int64(f4) * int64(f4) + f4f5_2 := int64(f4_2) * int64(f5) + f4f6_38 := int64(f4_2) * int64(f6_19) + f4f7_38 := int64(f4) * int64(f7_38) + f4f8_38 := int64(f4_2) * int64(f8_19) + f4f9_38 := int64(f4) * int64(f9_38) + f5f5_38 := int64(f5) * int64(f5_38) + f5f6_38 := int64(f5_2) * int64(f6_19) + f5f7_76 := int64(f5_2) * int64(f7_38) + f5f8_38 := int64(f5_2) * int64(f8_19) + f5f9_76 := int64(f5_2) * int64(f9_38) + f6f6_19 := int64(f6) * int64(f6_19) + f6f7_38 := int64(f6) * int64(f7_38) + f6f8_38 := int64(f6_2) * int64(f8_19) + f6f9_38 := int64(f6) * int64(f9_38) + f7f7_38 := int64(f7) * int64(f7_38) + f7f8_38 := int64(f7_2) * int64(f8_19) + f7f9_76 := int64(f7_2) * int64(f9_38) + f8f8_19 := int64(f8) * int64(f8_19) + f8f9_38 := int64(f8) * int64(f9_38) + f9f9_38 := int64(f9) * int64(f9_38) + h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 + h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 + h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 + h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 + h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 + h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 + h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 + h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 + h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 + h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 + var carry [10]int64 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feMul121666 calculates h = f * 121666. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func feMul121666(h, f *fieldElement) { + h0 := int64(f[0]) * 121666 + h1 := int64(f[1]) * 121666 + h2 := int64(f[2]) * 121666 + h3 := int64(f[3]) * 121666 + h4 := int64(f[4]) * 121666 + h5 := int64(f[5]) * 121666 + h6 := int64(f[6]) * 121666 + h7 := int64(f[7]) * 121666 + h8 := int64(f[8]) * 121666 + h9 := int64(f[9]) * 121666 + var carry [10]int64 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feInvert sets out = z^-1. +func feInvert(out, z *fieldElement) { + var t0, t1, t2, t3 fieldElement + var i int + + feSquare(&t0, z) + for i = 1; i < 1; i++ { + feSquare(&t0, &t0) + } + feSquare(&t1, &t0) + for i = 1; i < 2; i++ { + feSquare(&t1, &t1) + } + feMul(&t1, z, &t1) + feMul(&t0, &t0, &t1) + feSquare(&t2, &t0) + for i = 1; i < 1; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t1, &t2) + feSquare(&t2, &t1) + for i = 1; i < 5; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t2, &t1) + for i = 1; i < 10; i++ { + feSquare(&t2, &t2) + } + feMul(&t2, &t2, &t1) + feSquare(&t3, &t2) + for i = 1; i < 20; i++ { + feSquare(&t3, &t3) + } + feMul(&t2, &t3, &t2) + feSquare(&t2, &t2) + for i = 1; i < 10; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t2, &t1) + for i = 1; i < 50; i++ { + feSquare(&t2, &t2) + } + feMul(&t2, &t2, &t1) + feSquare(&t3, &t2) + for i = 1; i < 100; i++ { + feSquare(&t3, &t3) + } + feMul(&t2, &t3, &t2) + feSquare(&t2, &t2) + for i = 1; i < 50; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t1, &t1) + for i = 1; i < 5; i++ { + feSquare(&t1, &t1) + } + feMul(out, &t1, &t0) +} + +func scalarMult(out, in, base *[32]byte) { + var e [32]byte + + copy(e[:], in[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement + feFromBytes(&x1, base) + feOne(&x2) + feCopy(&x3, &x1) + feOne(&z3) + + swap := int32(0) + for pos := 254; pos >= 0; pos-- { + b := e[pos/8] >> uint(pos&7) + b &= 1 + swap ^= int32(b) + feCSwap(&x2, &x3, swap) + feCSwap(&z2, &z3, swap) + swap = int32(b) + + feSub(&tmp0, &x3, &z3) + feSub(&tmp1, &x2, &z2) + feAdd(&x2, &x2, &z2) + feAdd(&z2, &x3, &z3) + feMul(&z3, &tmp0, &x2) + feMul(&z2, &z2, &tmp1) + feSquare(&tmp0, &tmp1) + feSquare(&tmp1, &x2) + feAdd(&x3, &z3, &z2) + feSub(&z2, &z3, &z2) + feMul(&x2, &tmp1, &tmp0) + feSub(&tmp1, &tmp1, &tmp0) + feSquare(&z2, &z2) + feMul121666(&z3, &tmp1) + feSquare(&x3, &x3) + feAdd(&tmp0, &tmp0, &z3) + feMul(&z3, &x1, &z2) + feMul(&z2, &tmp1, &tmp0) + } + + feCSwap(&x2, &x3, swap) + feCSwap(&z2, &z3, swap) + + feInvert(&z2, &z2) + feMul(&x2, &x2, &z2) + feToBytes(out, &x2) +} diff --git a/vendor/github.com/keybase/go-crypto/curve25519/curve_impl.go b/vendor/github.com/keybase/go-crypto/curve25519/curve_impl.go new file mode 100644 index 000000000..5f9eebebf --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/curve_impl.go @@ -0,0 +1,113 @@ +package curve25519 + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +var cv25519 cv25519Curve + +type cv25519Curve struct { + *elliptic.CurveParams +} + +func copyReverse(dst []byte, src []byte) { + // Curve 25519 multiplication functions expect scalars in reverse + // order than PGP. To keep the curve25519Curve type consistent + // with other curves, we reverse it here. + for i, j := 0, len(src)-1; j >= 0; i, j = i+1, j-1 { + dst[i] = src[j] + } +} + +func (cv25519Curve) ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) { + // Assume y1 is 0 with cv25519. + var dst [32]byte + var x1Bytes [32]byte + var scalarBytes [32]byte + + copy(x1Bytes[:], x1.Bytes()[:32]) + copyReverse(scalarBytes[:], scalar[:32]) + + scalarMult(&dst, &scalarBytes, &x1Bytes) + + x = new(big.Int).SetBytes(dst[:]) + y = new(big.Int) + return x, y +} + +func (cv25519Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { + var dst [32]byte + var scalarBytes [32]byte + copyReverse(scalarBytes[:], scalar[:32]) + scalarMult(&dst, &scalarBytes, &basePoint) + x = new(big.Int).SetBytes(dst[:]) + y = new(big.Int) + return x, y +} + +func (cv25519Curve) IsOnCurve(bigX, bigY *big.Int) bool { + return bigY.Sign() == 0 // bigY == 0 ? +} + +// More information about 0x40 point format: +// https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-00#section-3 +// In addition to uncompressed point format described here: +// https://tools.ietf.org/html/rfc6637#section-6 + +func (cv25519Curve) MarshalType40(x, y *big.Int) []byte { + byteLen := 32 + + ret := make([]byte, 1+byteLen) + ret[0] = 0x40 + + xBytes := x.Bytes() + copy(ret[1+byteLen-len(xBytes):], xBytes) + return ret +} + +func (cv25519Curve) UnmarshalType40(data []byte) (x, y *big.Int) { + if len(data) != 1+32 { + return nil, nil + } + if data[0] != 0x40 { + return nil, nil + } + x = new(big.Int).SetBytes(data[1:]) + // Any x is a valid curve point. + return x, new(big.Int) +} + +// ToCurve25519 casts given elliptic.Curve type to Curve25519 type, or +// returns nil, false if cast was unsuccessful. +func ToCurve25519(cv elliptic.Curve) (cv25519Curve, bool) { + cv2, ok := cv.(cv25519Curve) + return cv2, ok +} + +func initCv25519() { + cv25519.CurveParams = &elliptic.CurveParams{Name: "Curve 25519"} + // Some code relies on these parameters being available for + // checking Curve coordinate length. They should not be used + // directly for any calculations. + cv25519.P, _ = new (big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16) + cv25519.N, _ = new (big.Int).SetString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16) + cv25519.Gx, _ = new (big.Int).SetString("9", 16) + cv25519.Gy, _ = new (big.Int).SetString("20ae19a1b8a086b4e01edd2c7748d14c923d4d7e6d7c61b229e9c5a27eced3d9", 16) + cv25519.BitSize = 256 +} + +var initonce sync.Once + +// Cv25519 returns a Curve which (partially) implements Cv25519. Only +// ScalarMult and ScalarBaseMult are valid for this curve. Add and +// Double should not be used. +func Cv25519() elliptic.Curve { + initonce.Do(initCv25519) + return cv25519 +} + +func (curve cv25519Curve) Params() *elliptic.CurveParams { + return curve.CurveParams +} diff --git a/vendor/github.com/keybase/go-crypto/curve25519/doc.go b/vendor/github.com/keybase/go-crypto/curve25519/doc.go new file mode 100644 index 000000000..f7db9c1ce --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/doc.go @@ -0,0 +1,23 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package curve25519 provides an implementation of scalar multiplication on +// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html +package curve25519 + +// basePoint is the x coordinate of the generator of the curve. +var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +// ScalarMult sets dst to the product in*base where dst and base are the x +// coordinates of group points and all values are in little-endian form. +func ScalarMult(dst, in, base *[32]byte) { + scalarMult(dst, in, base) +} + +// ScalarBaseMult sets dst to the product in*base where dst and base are the x +// coordinates of group points, base is the standard generator and all values +// are in little-endian form. +func ScalarBaseMult(dst, in *[32]byte) { + ScalarMult(dst, in, &basePoint) +} diff --git a/vendor/github.com/keybase/go-crypto/curve25519/freeze_amd64.s b/vendor/github.com/keybase/go-crypto/curve25519/freeze_amd64.s new file mode 100644 index 000000000..37599fac0 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/freeze_amd64.s @@ -0,0 +1,94 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func freeze(inout *[5]uint64) +TEXT ·freeze(SB),7,$96-8 + MOVQ inout+0(FP), DI + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32,SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ 0(DI),SI + MOVQ 8(DI),DX + MOVQ 16(DI),CX + MOVQ 24(DI),R8 + MOVQ 32(DI),R9 + MOVQ ·REDMASK51(SB),AX + MOVQ AX,R10 + SUBQ $18,R10 + MOVQ $3,R11 +REDUCELOOP: + MOVQ SI,R12 + SHRQ $51,R12 + ANDQ AX,SI + ADDQ R12,DX + MOVQ DX,R12 + SHRQ $51,R12 + ANDQ AX,DX + ADDQ R12,CX + MOVQ CX,R12 + SHRQ $51,R12 + ANDQ AX,CX + ADDQ R12,R8 + MOVQ R8,R12 + SHRQ $51,R12 + ANDQ AX,R8 + ADDQ R12,R9 + MOVQ R9,R12 + SHRQ $51,R12 + ANDQ AX,R9 + IMUL3Q $19,R12,R12 + ADDQ R12,SI + SUBQ $1,R11 + JA REDUCELOOP + MOVQ $1,R12 + CMPQ R10,SI + CMOVQLT R11,R12 + CMPQ AX,DX + CMOVQNE R11,R12 + CMPQ AX,CX + CMOVQNE R11,R12 + CMPQ AX,R8 + CMOVQNE R11,R12 + CMPQ AX,R9 + CMOVQNE R11,R12 + NEGQ R12 + ANDQ R12,AX + ANDQ R12,R10 + SUBQ R10,SI + SUBQ AX,DX + SUBQ AX,CX + SUBQ AX,R8 + SUBQ AX,R9 + MOVQ SI,0(DI) + MOVQ DX,8(DI) + MOVQ CX,16(DI) + MOVQ R8,24(DI) + MOVQ R9,32(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/keybase/go-crypto/curve25519/ladderstep_amd64.s b/vendor/github.com/keybase/go-crypto/curve25519/ladderstep_amd64.s new file mode 100644 index 000000000..3949f9cfa --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/ladderstep_amd64.s @@ -0,0 +1,1398 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func ladderstep(inout *[5][5]uint64) +TEXT ·ladderstep(SB),0,$384-8 + MOVQ inout+0(FP),DI + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32,SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ 40(DI),SI + MOVQ 48(DI),DX + MOVQ 56(DI),CX + MOVQ 64(DI),R8 + MOVQ 72(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 80(DI),SI + ADDQ 88(DI),DX + ADDQ 96(DI),CX + ADDQ 104(DI),R8 + ADDQ 112(DI),R9 + SUBQ 80(DI),AX + SUBQ 88(DI),R10 + SUBQ 96(DI),R11 + SUBQ 104(DI),R12 + SUBQ 112(DI),R13 + MOVQ SI,56(SP) + MOVQ DX,64(SP) + MOVQ CX,72(SP) + MOVQ R8,80(SP) + MOVQ R9,88(SP) + MOVQ AX,96(SP) + MOVQ R10,104(SP) + MOVQ R11,112(SP) + MOVQ R12,120(SP) + MOVQ R13,128(SP) + MOVQ 96(SP),AX + MULQ 96(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 104(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 112(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 120(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 96(SP),AX + SHLQ $1,AX + MULQ 128(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 104(SP),AX + MULQ 104(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 104(SP),AX + SHLQ $1,AX + MULQ 112(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 104(SP),AX + SHLQ $1,AX + MULQ 120(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 104(SP),DX + IMUL3Q $38,DX,AX + MULQ 128(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 112(SP),AX + MULQ 112(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 112(SP),DX + IMUL3Q $38,DX,AX + MULQ 120(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 112(SP),DX + IMUL3Q $38,DX,AX + MULQ 128(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 120(SP),DX + IMUL3Q $19,DX,AX + MULQ 120(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 120(SP),DX + IMUL3Q $38,DX,AX + MULQ 128(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(SP),DX + IMUL3Q $19,DX,AX + MULQ 128(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,136(SP) + MOVQ R8,144(SP) + MOVQ R9,152(SP) + MOVQ AX,160(SP) + MOVQ R10,168(SP) + MOVQ 56(SP),AX + MULQ 56(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 64(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 72(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 80(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 56(SP),AX + SHLQ $1,AX + MULQ 88(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 64(SP),AX + MULQ 64(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + SHLQ $1,AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 64(SP),AX + SHLQ $1,AX + MULQ 80(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),DX + IMUL3Q $38,DX,AX + MULQ 88(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 72(SP),AX + MULQ 72(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 72(SP),DX + IMUL3Q $38,DX,AX + MULQ 80(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 72(SP),DX + IMUL3Q $38,DX,AX + MULQ 88(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 80(SP),DX + IMUL3Q $19,DX,AX + MULQ 80(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 80(SP),DX + IMUL3Q $38,DX,AX + MULQ 88(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 88(SP),DX + IMUL3Q $19,DX,AX + MULQ 88(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,176(SP) + MOVQ R8,184(SP) + MOVQ R9,192(SP) + MOVQ AX,200(SP) + MOVQ R10,208(SP) + MOVQ SI,SI + MOVQ R8,DX + MOVQ R9,CX + MOVQ AX,R8 + MOVQ R10,R9 + ADDQ ·_2P0(SB),SI + ADDQ ·_2P1234(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R8 + ADDQ ·_2P1234(SB),R9 + SUBQ 136(SP),SI + SUBQ 144(SP),DX + SUBQ 152(SP),CX + SUBQ 160(SP),R8 + SUBQ 168(SP),R9 + MOVQ SI,216(SP) + MOVQ DX,224(SP) + MOVQ CX,232(SP) + MOVQ R8,240(SP) + MOVQ R9,248(SP) + MOVQ 120(DI),SI + MOVQ 128(DI),DX + MOVQ 136(DI),CX + MOVQ 144(DI),R8 + MOVQ 152(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 160(DI),SI + ADDQ 168(DI),DX + ADDQ 176(DI),CX + ADDQ 184(DI),R8 + ADDQ 192(DI),R9 + SUBQ 160(DI),AX + SUBQ 168(DI),R10 + SUBQ 176(DI),R11 + SUBQ 184(DI),R12 + SUBQ 192(DI),R13 + MOVQ SI,256(SP) + MOVQ DX,264(SP) + MOVQ CX,272(SP) + MOVQ R8,280(SP) + MOVQ R9,288(SP) + MOVQ AX,296(SP) + MOVQ R10,304(SP) + MOVQ R11,312(SP) + MOVQ R12,320(SP) + MOVQ R13,328(SP) + MOVQ 280(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,336(SP) + MULQ 112(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 288(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,344(SP) + MULQ 104(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),AX + MULQ 96(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),AX + MULQ 104(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 256(SP),AX + MULQ 112(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 256(SP),AX + MULQ 120(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 256(SP),AX + MULQ 128(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 264(SP),AX + MULQ 96(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 264(SP),AX + MULQ 104(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 264(SP),AX + MULQ 112(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 264(SP),AX + MULQ 120(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 264(SP),DX + IMUL3Q $19,DX,AX + MULQ 128(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 272(SP),AX + MULQ 96(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 272(SP),AX + MULQ 104(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 272(SP),AX + MULQ 112(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 272(SP),DX + IMUL3Q $19,DX,AX + MULQ 120(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 272(SP),DX + IMUL3Q $19,DX,AX + MULQ 128(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 280(SP),AX + MULQ 96(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 280(SP),AX + MULQ 104(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 336(SP),AX + MULQ 120(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 336(SP),AX + MULQ 128(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 288(SP),AX + MULQ 96(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 344(SP),AX + MULQ 112(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 344(SP),AX + MULQ 120(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 344(SP),AX + MULQ 128(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,96(SP) + MOVQ R8,104(SP) + MOVQ R9,112(SP) + MOVQ AX,120(SP) + MOVQ R10,128(SP) + MOVQ 320(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,256(SP) + MULQ 72(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 328(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,264(SP) + MULQ 64(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 296(SP),AX + MULQ 56(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 296(SP),AX + MULQ 64(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 296(SP),AX + MULQ 72(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 296(SP),AX + MULQ 80(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 296(SP),AX + MULQ 88(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 304(SP),AX + MULQ 56(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 304(SP),AX + MULQ 64(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 304(SP),AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 304(SP),AX + MULQ 80(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 304(SP),DX + IMUL3Q $19,DX,AX + MULQ 88(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 312(SP),AX + MULQ 56(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 312(SP),AX + MULQ 64(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 312(SP),AX + MULQ 72(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 312(SP),DX + IMUL3Q $19,DX,AX + MULQ 80(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 312(SP),DX + IMUL3Q $19,DX,AX + MULQ 88(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 320(SP),AX + MULQ 56(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 320(SP),AX + MULQ 64(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 256(SP),AX + MULQ 80(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 256(SP),AX + MULQ 88(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 328(SP),AX + MULQ 56(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 264(SP),AX + MULQ 72(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 264(SP),AX + MULQ 80(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 264(SP),AX + MULQ 88(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,DX + MOVQ R8,CX + MOVQ R9,R11 + MOVQ AX,R12 + MOVQ R10,R13 + ADDQ ·_2P0(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 96(SP),SI + ADDQ 104(SP),R8 + ADDQ 112(SP),R9 + ADDQ 120(SP),AX + ADDQ 128(SP),R10 + SUBQ 96(SP),DX + SUBQ 104(SP),CX + SUBQ 112(SP),R11 + SUBQ 120(SP),R12 + SUBQ 128(SP),R13 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ DX,160(DI) + MOVQ CX,168(DI) + MOVQ R11,176(DI) + MOVQ R12,184(DI) + MOVQ R13,192(DI) + MOVQ 120(DI),AX + MULQ 120(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 128(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 136(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 144(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 152(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 128(DI),AX + MULQ 128(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 136(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 144(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 128(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),AX + MULQ 136(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 144(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $19,DX,AX + MULQ 144(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 152(DI),DX + IMUL3Q $19,DX,AX + MULQ 152(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ 160(DI),AX + MULQ 160(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 168(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 176(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 184(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 192(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 168(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 176(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 184(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 176(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 184(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $19,DX,AX + MULQ 184(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 184(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,56(SP) + MULQ 16(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 8(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 0(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 8(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + MULQ 16(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + MULQ 24(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + MULQ 32(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 0(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 168(DI),AX + MULQ 8(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + MULQ 16(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + MULQ 24(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 0(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 176(DI),AX + MULQ 8(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 176(DI),AX + MULQ 16(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 24(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),AX + MULQ 0(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 184(DI),AX + MULQ 8(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),AX + MULQ 24(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 56(SP),AX + MULQ 32(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),AX + MULQ 0(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),AX + MULQ 16(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),AX + MULQ 24(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 32(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 200(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,56(SP) + MULQ 152(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 208(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 144(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(SP),AX + MULQ 136(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(SP),AX + MULQ 144(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 176(SP),AX + MULQ 152(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 176(SP),AX + MULQ 160(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 176(SP),AX + MULQ 168(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 184(SP),AX + MULQ 136(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(SP),AX + MULQ 144(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 184(SP),AX + MULQ 152(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 184(SP),AX + MULQ 160(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 184(SP),DX + IMUL3Q $19,DX,AX + MULQ 168(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 192(SP),AX + MULQ 136(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(SP),AX + MULQ 144(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 192(SP),AX + MULQ 152(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 192(SP),DX + IMUL3Q $19,DX,AX + MULQ 160(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 192(SP),DX + IMUL3Q $19,DX,AX + MULQ 168(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 200(SP),AX + MULQ 136(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 200(SP),AX + MULQ 144(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),AX + MULQ 160(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 56(SP),AX + MULQ 168(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 208(SP),AX + MULQ 136(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),AX + MULQ 152(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),AX + MULQ 160(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 168(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,40(DI) + MOVQ R8,48(DI) + MOVQ R9,56(DI) + MOVQ AX,64(DI) + MOVQ R10,72(DI) + MOVQ 216(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + MOVQ AX,SI + MOVQ DX,CX + MOVQ 224(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,CX + MOVQ DX,R8 + MOVQ 232(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R8 + MOVQ DX,R9 + MOVQ 240(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R9 + MOVQ DX,R10 + MOVQ 248(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R10 + IMUL3Q $19,DX,DX + ADDQ DX,SI + ADDQ 136(SP),SI + ADDQ 144(SP),CX + ADDQ 152(SP),R8 + ADDQ 160(SP),R9 + ADDQ 168(SP),R10 + MOVQ SI,80(DI) + MOVQ CX,88(DI) + MOVQ R8,96(DI) + MOVQ R9,104(DI) + MOVQ R10,112(DI) + MOVQ 104(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,56(SP) + MULQ 232(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 112(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 224(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 216(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 224(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 80(DI),AX + MULQ 232(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 80(DI),AX + MULQ 240(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 80(DI),AX + MULQ 248(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 88(DI),AX + MULQ 216(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 88(DI),AX + MULQ 224(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 88(DI),AX + MULQ 232(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 88(DI),AX + MULQ 240(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 88(DI),DX + IMUL3Q $19,DX,AX + MULQ 248(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),AX + MULQ 216(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 96(DI),AX + MULQ 224(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 96(DI),AX + MULQ 232(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 240(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 248(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 104(DI),AX + MULQ 216(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 104(DI),AX + MULQ 224(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),AX + MULQ 240(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 56(SP),AX + MULQ 248(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 112(DI),AX + MULQ 216(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 64(SP),AX + MULQ 232(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),AX + MULQ 240(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 248(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ ·REDMASK51(SB),DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,80(DI) + MOVQ R8,88(DI) + MOVQ R9,96(DI) + MOVQ AX,104(DI) + MOVQ R10,112(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/keybase/go-crypto/curve25519/mont25519_amd64.go b/vendor/github.com/keybase/go-crypto/curve25519/mont25519_amd64.go new file mode 100644 index 000000000..5822bd533 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/mont25519_amd64.go @@ -0,0 +1,240 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +package curve25519 + +// These functions are implemented in the .s files. The names of the functions +// in the rest of the file are also taken from the SUPERCOP sources to help +// people following along. + +//go:noescape + +func cswap(inout *[5]uint64, v uint64) + +//go:noescape + +func ladderstep(inout *[5][5]uint64) + +//go:noescape + +func freeze(inout *[5]uint64) + +//go:noescape + +func mul(dest, a, b *[5]uint64) + +//go:noescape + +func square(out, in *[5]uint64) + +// mladder uses a Montgomery ladder to calculate (xr/zr) *= s. +func mladder(xr, zr *[5]uint64, s *[32]byte) { + var work [5][5]uint64 + + work[0] = *xr + setint(&work[1], 1) + setint(&work[2], 0) + work[3] = *xr + setint(&work[4], 1) + + j := uint(6) + var prevbit byte + + for i := 31; i >= 0; i-- { + for j < 8 { + bit := ((*s)[i] >> j) & 1 + swap := bit ^ prevbit + prevbit = bit + cswap(&work[1], uint64(swap)) + ladderstep(&work) + j-- + } + j = 7 + } + + *xr = work[1] + *zr = work[2] +} + +func scalarMult(out, in, base *[32]byte) { + var e [32]byte + copy(e[:], (*in)[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var t, z [5]uint64 + unpack(&t, base) + mladder(&t, &z, &e) + invert(&z, &z) + mul(&t, &t, &z) + pack(out, &t) +} + +func setint(r *[5]uint64, v uint64) { + r[0] = v + r[1] = 0 + r[2] = 0 + r[3] = 0 + r[4] = 0 +} + +// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian +// order. +func unpack(r *[5]uint64, x *[32]byte) { + r[0] = uint64(x[0]) | + uint64(x[1])<<8 | + uint64(x[2])<<16 | + uint64(x[3])<<24 | + uint64(x[4])<<32 | + uint64(x[5])<<40 | + uint64(x[6]&7)<<48 + + r[1] = uint64(x[6])>>3 | + uint64(x[7])<<5 | + uint64(x[8])<<13 | + uint64(x[9])<<21 | + uint64(x[10])<<29 | + uint64(x[11])<<37 | + uint64(x[12]&63)<<45 + + r[2] = uint64(x[12])>>6 | + uint64(x[13])<<2 | + uint64(x[14])<<10 | + uint64(x[15])<<18 | + uint64(x[16])<<26 | + uint64(x[17])<<34 | + uint64(x[18])<<42 | + uint64(x[19]&1)<<50 + + r[3] = uint64(x[19])>>1 | + uint64(x[20])<<7 | + uint64(x[21])<<15 | + uint64(x[22])<<23 | + uint64(x[23])<<31 | + uint64(x[24])<<39 | + uint64(x[25]&15)<<47 + + r[4] = uint64(x[25])>>4 | + uint64(x[26])<<4 | + uint64(x[27])<<12 | + uint64(x[28])<<20 | + uint64(x[29])<<28 | + uint64(x[30])<<36 | + uint64(x[31]&127)<<44 +} + +// pack sets out = x where out is the usual, little-endian form of the 5, +// 51-bit limbs in x. +func pack(out *[32]byte, x *[5]uint64) { + t := *x + freeze(&t) + + out[0] = byte(t[0]) + out[1] = byte(t[0] >> 8) + out[2] = byte(t[0] >> 16) + out[3] = byte(t[0] >> 24) + out[4] = byte(t[0] >> 32) + out[5] = byte(t[0] >> 40) + out[6] = byte(t[0] >> 48) + + out[6] ^= byte(t[1]<<3) & 0xf8 + out[7] = byte(t[1] >> 5) + out[8] = byte(t[1] >> 13) + out[9] = byte(t[1] >> 21) + out[10] = byte(t[1] >> 29) + out[11] = byte(t[1] >> 37) + out[12] = byte(t[1] >> 45) + + out[12] ^= byte(t[2]<<6) & 0xc0 + out[13] = byte(t[2] >> 2) + out[14] = byte(t[2] >> 10) + out[15] = byte(t[2] >> 18) + out[16] = byte(t[2] >> 26) + out[17] = byte(t[2] >> 34) + out[18] = byte(t[2] >> 42) + out[19] = byte(t[2] >> 50) + + out[19] ^= byte(t[3]<<1) & 0xfe + out[20] = byte(t[3] >> 7) + out[21] = byte(t[3] >> 15) + out[22] = byte(t[3] >> 23) + out[23] = byte(t[3] >> 31) + out[24] = byte(t[3] >> 39) + out[25] = byte(t[3] >> 47) + + out[25] ^= byte(t[4]<<4) & 0xf0 + out[26] = byte(t[4] >> 4) + out[27] = byte(t[4] >> 12) + out[28] = byte(t[4] >> 20) + out[29] = byte(t[4] >> 28) + out[30] = byte(t[4] >> 36) + out[31] = byte(t[4] >> 44) +} + +// invert calculates r = x^-1 mod p using Fermat's little theorem. +func invert(r *[5]uint64, x *[5]uint64) { + var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 + + square(&z2, x) /* 2 */ + square(&t, &z2) /* 4 */ + square(&t, &t) /* 8 */ + mul(&z9, &t, x) /* 9 */ + mul(&z11, &z9, &z2) /* 11 */ + square(&t, &z11) /* 22 */ + mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ + + square(&t, &z2_5_0) /* 2^6 - 2^1 */ + for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ + square(&t, &t) + } + mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ + + square(&t, &z2_10_0) /* 2^11 - 2^1 */ + for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ + square(&t, &t) + } + mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ + + square(&t, &z2_20_0) /* 2^21 - 2^1 */ + for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ + square(&t, &t) + } + mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ + + square(&t, &t) /* 2^41 - 2^1 */ + for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ + square(&t, &t) + } + mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ + + square(&t, &z2_50_0) /* 2^51 - 2^1 */ + for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ + square(&t, &t) + } + mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ + + square(&t, &z2_100_0) /* 2^101 - 2^1 */ + for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ + square(&t, &t) + } + mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ + + square(&t, &t) /* 2^201 - 2^1 */ + for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ + square(&t, &t) + } + mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ + + square(&t, &t) /* 2^251 - 2^1 */ + square(&t, &t) /* 2^252 - 2^2 */ + square(&t, &t) /* 2^253 - 2^3 */ + + square(&t, &t) /* 2^254 - 2^4 */ + + square(&t, &t) /* 2^255 - 2^5 */ + mul(r, &t, &z11) /* 2^255 - 21 */ +} diff --git a/vendor/github.com/keybase/go-crypto/curve25519/mul_amd64.s b/vendor/github.com/keybase/go-crypto/curve25519/mul_amd64.s new file mode 100644 index 000000000..e48d183ee --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/mul_amd64.s @@ -0,0 +1,191 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func mul(dest, a, b *[5]uint64) +TEXT ·mul(SB),0,$128-24 + MOVQ dest+0(FP), DI + MOVQ a+8(FP), SI + MOVQ b+16(FP), DX + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32,SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ DI,56(SP) + MOVQ DX,CX + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,64(SP) + MULQ 16(CX) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,72(SP) + MULQ 8(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 0(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 8(CX) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 0(SI),AX + MULQ 16(CX) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 0(SI),AX + MULQ 24(CX) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 0(SI),AX + MULQ 32(CX) + MOVQ AX,BX + MOVQ DX,BP + MOVQ 8(SI),AX + MULQ 0(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SI),AX + MULQ 8(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SI),AX + MULQ 16(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SI),AX + MULQ 24(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 8(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),AX + MULQ 0(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 16(SI),AX + MULQ 8(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 16(SI),AX + MULQ 16(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 24(SI),AX + MULQ 0(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 24(SI),AX + MULQ 8(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 64(SP),AX + MULQ 24(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 64(SP),AX + MULQ 32(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 32(SI),AX + MULQ 0(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 72(SP),AX + MULQ 16(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 72(SP),AX + MULQ 24(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 72(SP),AX + MULQ 32(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ ·REDMASK51(SB),SI + SHLQ $13,R9:R8 + ANDQ SI,R8 + SHLQ $13,R11:R10 + ANDQ SI,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ SI,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ SI,R14 + ADDQ R13,R14 + SHLQ $13,BP:BX + ANDQ SI,BX + ADDQ R15,BX + IMUL3Q $19,BP,DX + ADDQ DX,R8 + MOVQ R8,DX + SHRQ $51,DX + ADDQ R10,DX + MOVQ DX,CX + SHRQ $51,DX + ANDQ SI,R8 + ADDQ R12,DX + MOVQ DX,R9 + SHRQ $51,DX + ANDQ SI,CX + ADDQ R14,DX + MOVQ DX,AX + SHRQ $51,DX + ANDQ SI,R9 + ADDQ BX,DX + MOVQ DX,R10 + SHRQ $51,DX + ANDQ SI,AX + IMUL3Q $19,DX,DX + ADDQ DX,R8 + ANDQ SI,R10 + MOVQ R8,0(DI) + MOVQ CX,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/keybase/go-crypto/curve25519/square_amd64.s b/vendor/github.com/keybase/go-crypto/curve25519/square_amd64.s new file mode 100644 index 000000000..78d1a50dd --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/curve25519/square_amd64.s @@ -0,0 +1,153 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// func square(out, in *[5]uint64) +TEXT ·square(SB),7,$96-16 + MOVQ out+0(FP), DI + MOVQ in+8(FP), SI + + MOVQ SP,R11 + MOVQ $31,CX + NOTQ CX + ANDQ CX,SP + ADDQ $32, SP + + MOVQ R11,0(SP) + MOVQ R12,8(SP) + MOVQ R13,16(SP) + MOVQ R14,24(SP) + MOVQ R15,32(SP) + MOVQ BX,40(SP) + MOVQ BP,48(SP) + MOVQ 0(SI),AX + MULQ 0(SI) + MOVQ AX,CX + MOVQ DX,R8 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 8(SI) + MOVQ AX,R9 + MOVQ DX,R10 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 16(SI) + MOVQ AX,R11 + MOVQ DX,R12 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 24(SI) + MOVQ AX,R13 + MOVQ DX,R14 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 32(SI) + MOVQ AX,R15 + MOVQ DX,BX + MOVQ 8(SI),AX + MULQ 8(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 16(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 24(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 8(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),AX + MULQ 16(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 24(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ ·REDMASK51(SB),SI + SHLQ $13,R8:CX + ANDQ SI,CX + SHLQ $13,R10:R9 + ANDQ SI,R9 + ADDQ R8,R9 + SHLQ $13,R12:R11 + ANDQ SI,R11 + ADDQ R10,R11 + SHLQ $13,R14:R13 + ANDQ SI,R13 + ADDQ R12,R13 + SHLQ $13,BX:R15 + ANDQ SI,R15 + ADDQ R14,R15 + IMUL3Q $19,BX,DX + ADDQ DX,CX + MOVQ CX,DX + SHRQ $51,DX + ADDQ R9,DX + ANDQ SI,CX + MOVQ DX,R8 + SHRQ $51,DX + ADDQ R11,DX + ANDQ SI,R8 + MOVQ DX,R9 + SHRQ $51,DX + ADDQ R13,DX + ANDQ SI,R9 + MOVQ DX,AX + SHRQ $51,DX + ADDQ R15,DX + ANDQ SI,AX + MOVQ DX,R10 + SHRQ $51,DX + IMUL3Q $19,DX,DX + ADDQ DX,CX + ANDQ SI,R10 + MOVQ CX,0(DI) + MOVQ R8,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + MOVQ 0(SP),R11 + MOVQ 8(SP),R12 + MOVQ 16(SP),R13 + MOVQ 24(SP),R14 + MOVQ 32(SP),R15 + MOVQ 40(SP),BX + MOVQ 48(SP),BP + MOVQ R11,SP + MOVQ DI,AX + MOVQ SI,DX + RET diff --git a/vendor/github.com/keybase/go-crypto/ed25519/ed25519.go b/vendor/github.com/keybase/go-crypto/ed25519/ed25519.go new file mode 100644 index 000000000..41a146e45 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/ed25519/ed25519.go @@ -0,0 +1,188 @@ +// 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. + +// Package ed25519 implements the Ed25519 signature algorithm. See +// http://ed25519.cr.yp.to/. +// +// These functions are also compatible with the “Ed25519” function defined in +// RFC 8032. +package ed25519 + +// This code is a port of the public domain, “ref10” implementation of ed25519 +// from SUPERCOP. + +import ( + "bytes" + "crypto" + cryptorand "crypto/rand" + "crypto/sha512" + "errors" + "io" + "strconv" + + "github.com/keybase/go-crypto/ed25519/internal/edwards25519" +) + +const ( + // PublicKeySize is the size, in bytes, of public keys as used in this package. + PublicKeySize = 32 + // PrivateKeySize is the size, in bytes, of private keys as used in this package. + PrivateKeySize = 64 + // SignatureSize is the size, in bytes, of signatures generated and verified by this package. + SignatureSize = 64 +) + +// PublicKey is the type of Ed25519 public keys. +type PublicKey []byte + +// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. +type PrivateKey []byte + +// Public returns the PublicKey corresponding to priv. +func (priv PrivateKey) Public() crypto.PublicKey { + publicKey := make([]byte, PublicKeySize) + copy(publicKey, priv[32:]) + return PublicKey(publicKey) +} + +// Sign signs the given message with priv. +// Ed25519 performs two passes over messages to be signed and therefore cannot +// handle pre-hashed messages. Thus opts.HashFunc() must return zero to +// indicate the message hasn't been hashed. This can be achieved by passing +// crypto.Hash(0) as the value for opts. +func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { + if opts.HashFunc() != crypto.Hash(0) { + return nil, errors.New("ed25519: cannot sign hashed message") + } + + return Sign(priv, message), nil +} + +// GenerateKey generates a public/private key pair using entropy from rand. +// If rand is nil, crypto/rand.Reader will be used. +func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) { + if rand == nil { + rand = cryptorand.Reader + } + + privateKey = make([]byte, PrivateKeySize) + publicKey = make([]byte, PublicKeySize) + _, err = io.ReadFull(rand, privateKey[:32]) + if err != nil { + return nil, nil, err + } + + digest := sha512.Sum512(privateKey[:32]) + digest[0] &= 248 + digest[31] &= 127 + digest[31] |= 64 + + var A edwards25519.ExtendedGroupElement + var hBytes [32]byte + copy(hBytes[:], digest[:]) + edwards25519.GeScalarMultBase(&A, &hBytes) + var publicKeyBytes [32]byte + A.ToBytes(&publicKeyBytes) + + copy(privateKey[32:], publicKeyBytes[:]) + copy(publicKey, publicKeyBytes[:]) + + return publicKey, privateKey, nil +} + +// Sign signs the message with privateKey and returns a signature. It will +// panic if len(privateKey) is not PrivateKeySize. +func Sign(privateKey PrivateKey, message []byte) []byte { + if l := len(privateKey); l != PrivateKeySize { + panic("ed25519: bad private key length: " + strconv.Itoa(l)) + } + + h := sha512.New() + h.Write(privateKey[:32]) + + var digest1, messageDigest, hramDigest [64]byte + var expandedSecretKey [32]byte + h.Sum(digest1[:0]) + copy(expandedSecretKey[:], digest1[:]) + expandedSecretKey[0] &= 248 + expandedSecretKey[31] &= 63 + expandedSecretKey[31] |= 64 + + h.Reset() + h.Write(digest1[32:]) + h.Write(message) + h.Sum(messageDigest[:0]) + + var messageDigestReduced [32]byte + edwards25519.ScReduce(&messageDigestReduced, &messageDigest) + var R edwards25519.ExtendedGroupElement + edwards25519.GeScalarMultBase(&R, &messageDigestReduced) + + var encodedR [32]byte + R.ToBytes(&encodedR) + + h.Reset() + h.Write(encodedR[:]) + h.Write(privateKey[32:]) + h.Write(message) + h.Sum(hramDigest[:0]) + var hramDigestReduced [32]byte + edwards25519.ScReduce(&hramDigestReduced, &hramDigest) + + var s [32]byte + edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) + + signature := make([]byte, SignatureSize) + copy(signature[:], encodedR[:]) + copy(signature[32:], s[:]) + + return signature +} + +// Verify reports whether sig is a valid signature of message by publicKey. It +// will panic if len(publicKey) is not PublicKeySize. +func Verify(publicKey PublicKey, message, sig []byte) bool { + if l := len(publicKey); l != PublicKeySize { + panic("ed25519: bad public key length: " + strconv.Itoa(l)) + } + + if len(sig) != SignatureSize || sig[63]&224 != 0 { + return false + } + + var A edwards25519.ExtendedGroupElement + var publicKeyBytes [32]byte + copy(publicKeyBytes[:], publicKey) + if !A.FromBytes(&publicKeyBytes) { + return false + } + edwards25519.FeNeg(&A.X, &A.X) + edwards25519.FeNeg(&A.T, &A.T) + + h := sha512.New() + h.Write(sig[:32]) + h.Write(publicKey[:]) + h.Write(message) + var digest [64]byte + h.Sum(digest[:0]) + + var hReduced [32]byte + edwards25519.ScReduce(&hReduced, &digest) + + var R edwards25519.ProjectiveGroupElement + var s [32]byte + copy(s[:], sig[32:]) + + // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in + // the range [0, order) in order to prevent signature malleability. + if !edwards25519.ScMinimal(&s) { + return false + } + + edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) + + var checkR [32]byte + R.ToBytes(&checkR) + return bytes.Equal(sig[:32], checkR[:]) +} diff --git a/vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/const.go b/vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/const.go new file mode 100644 index 000000000..e39f086c1 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/const.go @@ -0,0 +1,1422 @@ +// 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. + +package edwards25519 + +// These values are from the public domain, “ref10” implementation of ed25519 +// from SUPERCOP. + +// d is a constant in the Edwards curve equation. +var d = FieldElement{ + -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116, +} + +// d2 is 2*d. +var d2 = FieldElement{ + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199, +} + +// SqrtM1 is the square-root of -1 in the field. +var SqrtM1 = FieldElement{ + -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482, +} + +// A is a constant in the Montgomery-form of curve25519. +var A = FieldElement{ + 486662, 0, 0, 0, 0, 0, 0, 0, 0, 0, +} + +// bi contains precomputed multiples of the base-point. See the Ed25519 paper +// for a discussion about how these values are used. +var bi = [8]PreComputedGroupElement{ + { + FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + FieldElement{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + FieldElement{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}, + }, + { + FieldElement{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + FieldElement{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + FieldElement{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}, + }, + { + FieldElement{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + FieldElement{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + FieldElement{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}, + }, + { + FieldElement{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + FieldElement{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + FieldElement{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}, + }, + { + FieldElement{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877}, + FieldElement{-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951}, + FieldElement{4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}, + }, + { + FieldElement{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436}, + FieldElement{25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918}, + FieldElement{23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}, + }, + { + FieldElement{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800}, + FieldElement{-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305}, + FieldElement{-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}, + }, + { + FieldElement{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876}, + FieldElement{-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619}, + FieldElement{-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}, + }, +} + +// base contains precomputed multiples of the base-point. See the Ed25519 paper +// for a discussion about how these values are used. +var base = [32][8]PreComputedGroupElement{ + { + { + FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + FieldElement{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + FieldElement{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}, + }, + { + FieldElement{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303}, + FieldElement{-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081}, + FieldElement{26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}, + }, + { + FieldElement{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + FieldElement{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + FieldElement{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}, + }, + { + FieldElement{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540}, + FieldElement{23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397}, + FieldElement{7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}, + }, + { + FieldElement{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + FieldElement{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + FieldElement{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}, + }, + { + FieldElement{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777}, + FieldElement{-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737}, + FieldElement{-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}, + }, + { + FieldElement{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + FieldElement{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + FieldElement{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}, + }, + { + FieldElement{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726}, + FieldElement{-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955}, + FieldElement{27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}, + }, + }, + { + { + FieldElement{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171}, + FieldElement{27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510}, + FieldElement{17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}, + }, + { + FieldElement{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639}, + FieldElement{29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963}, + FieldElement{5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}, + }, + { + FieldElement{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568}, + FieldElement{12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335}, + FieldElement{25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}, + }, + { + FieldElement{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007}, + FieldElement{-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772}, + FieldElement{-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}, + }, + { + FieldElement{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567}, + FieldElement{13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686}, + FieldElement{21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}, + }, + { + FieldElement{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887}, + FieldElement{-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954}, + FieldElement{-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}, + }, + { + FieldElement{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833}, + FieldElement{-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532}, + FieldElement{-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}, + }, + { + FieldElement{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268}, + FieldElement{33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214}, + FieldElement{1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}, + }, + }, + { + { + FieldElement{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800}, + FieldElement{4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645}, + FieldElement{-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}, + }, + { + FieldElement{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933}, + FieldElement{-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182}, + FieldElement{-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}, + }, + { + FieldElement{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991}, + FieldElement{20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880}, + FieldElement{9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}, + }, + { + FieldElement{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295}, + FieldElement{19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788}, + FieldElement{8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}, + }, + { + FieldElement{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026}, + FieldElement{11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347}, + FieldElement{-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}, + }, + { + FieldElement{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395}, + FieldElement{-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278}, + FieldElement{1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}, + }, + { + FieldElement{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995}, + FieldElement{-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596}, + FieldElement{-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}, + }, + { + FieldElement{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060}, + FieldElement{11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608}, + FieldElement{-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}, + }, + }, + { + { + FieldElement{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389}, + FieldElement{-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016}, + FieldElement{-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}, + }, + { + FieldElement{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505}, + FieldElement{14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553}, + FieldElement{-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}, + }, + { + FieldElement{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220}, + FieldElement{12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631}, + FieldElement{-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}, + }, + { + FieldElement{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556}, + FieldElement{14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749}, + FieldElement{236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}, + }, + { + FieldElement{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391}, + FieldElement{5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253}, + FieldElement{20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}, + }, + { + FieldElement{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958}, + FieldElement{-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082}, + FieldElement{-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}, + }, + { + FieldElement{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521}, + FieldElement{-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807}, + FieldElement{23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}, + }, + { + FieldElement{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134}, + FieldElement{-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455}, + FieldElement{27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}, + }, + }, + { + { + FieldElement{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069}, + FieldElement{-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746}, + FieldElement{24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}, + }, + { + FieldElement{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837}, + FieldElement{8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906}, + FieldElement{-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}, + }, + { + FieldElement{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817}, + FieldElement{10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098}, + FieldElement{10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}, + }, + { + FieldElement{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504}, + FieldElement{-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727}, + FieldElement{28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}, + }, + { + FieldElement{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003}, + FieldElement{-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605}, + FieldElement{-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}, + }, + { + FieldElement{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701}, + FieldElement{-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683}, + FieldElement{29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}, + }, + { + FieldElement{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563}, + FieldElement{-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260}, + FieldElement{-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}, + }, + { + FieldElement{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672}, + FieldElement{23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686}, + FieldElement{-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}, + }, + }, + { + { + FieldElement{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182}, + FieldElement{-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277}, + FieldElement{14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}, + }, + { + FieldElement{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474}, + FieldElement{-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539}, + FieldElement{-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}, + }, + { + FieldElement{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970}, + FieldElement{19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756}, + FieldElement{-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}, + }, + { + FieldElement{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683}, + FieldElement{-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655}, + FieldElement{-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}, + }, + { + FieldElement{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125}, + FieldElement{-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839}, + FieldElement{-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}, + }, + { + FieldElement{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294}, + FieldElement{-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899}, + FieldElement{-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}, + }, + { + FieldElement{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294}, + FieldElement{-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949}, + FieldElement{-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}, + }, + { + FieldElement{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420}, + FieldElement{-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940}, + FieldElement{29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}, + }, + }, + { + { + FieldElement{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567}, + FieldElement{20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127}, + FieldElement{-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}, + }, + { + FieldElement{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887}, + FieldElement{22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964}, + FieldElement{16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}, + }, + { + FieldElement{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244}, + FieldElement{24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999}, + FieldElement{-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}, + }, + { + FieldElement{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274}, + FieldElement{-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236}, + FieldElement{-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}, + }, + { + FieldElement{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761}, + FieldElement{-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884}, + FieldElement{-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}, + }, + { + FieldElement{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638}, + FieldElement{-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490}, + FieldElement{-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}, + }, + { + FieldElement{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736}, + FieldElement{10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124}, + FieldElement{-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}, + }, + { + FieldElement{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029}, + FieldElement{6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048}, + FieldElement{28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}, + }, + }, + { + { + FieldElement{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593}, + FieldElement{26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071}, + FieldElement{-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}, + }, + { + FieldElement{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687}, + FieldElement{-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441}, + FieldElement{-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}, + }, + { + FieldElement{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460}, + FieldElement{-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007}, + FieldElement{-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}, + }, + { + FieldElement{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005}, + FieldElement{-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674}, + FieldElement{4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}, + }, + { + FieldElement{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590}, + FieldElement{-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957}, + FieldElement{-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}, + }, + { + FieldElement{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740}, + FieldElement{-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122}, + FieldElement{-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}, + }, + { + FieldElement{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885}, + FieldElement{26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140}, + FieldElement{19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}, + }, + { + FieldElement{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155}, + FieldElement{19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260}, + FieldElement{19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}, + }, + }, + { + { + FieldElement{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677}, + FieldElement{32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815}, + FieldElement{22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}, + }, + { + FieldElement{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203}, + FieldElement{-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208}, + FieldElement{1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}, + }, + { + FieldElement{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850}, + FieldElement{-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389}, + FieldElement{-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}, + }, + { + FieldElement{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689}, + FieldElement{14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880}, + FieldElement{5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}, + }, + { + FieldElement{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632}, + FieldElement{-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412}, + FieldElement{20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}, + }, + { + FieldElement{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038}, + FieldElement{-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232}, + FieldElement{-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}, + }, + { + FieldElement{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856}, + FieldElement{23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738}, + FieldElement{15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}, + }, + { + FieldElement{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718}, + FieldElement{-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697}, + FieldElement{-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}, + }, + }, + { + { + FieldElement{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912}, + FieldElement{-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358}, + FieldElement{3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}, + }, + { + FieldElement{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307}, + FieldElement{-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977}, + FieldElement{-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}, + }, + { + FieldElement{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644}, + FieldElement{-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616}, + FieldElement{-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}, + }, + { + FieldElement{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099}, + FieldElement{29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341}, + FieldElement{-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}, + }, + { + FieldElement{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646}, + FieldElement{31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425}, + FieldElement{-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}, + }, + { + FieldElement{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743}, + FieldElement{-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822}, + FieldElement{-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}, + }, + { + FieldElement{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985}, + FieldElement{9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702}, + FieldElement{-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}, + }, + { + FieldElement{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293}, + FieldElement{27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100}, + FieldElement{19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}, + }, + }, + { + { + FieldElement{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186}, + FieldElement{2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610}, + FieldElement{-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}, + }, + { + FieldElement{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220}, + FieldElement{915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025}, + FieldElement{32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}, + }, + { + FieldElement{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992}, + FieldElement{-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027}, + FieldElement{21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}, + }, + { + FieldElement{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901}, + FieldElement{31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952}, + FieldElement{19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}, + }, + { + FieldElement{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390}, + FieldElement{32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730}, + FieldElement{2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}, + }, + { + FieldElement{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180}, + FieldElement{-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272}, + FieldElement{-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}, + }, + { + FieldElement{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970}, + FieldElement{-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772}, + FieldElement{-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}, + }, + { + FieldElement{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750}, + FieldElement{20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373}, + FieldElement{32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}, + }, + }, + { + { + FieldElement{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144}, + FieldElement{-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195}, + FieldElement{5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}, + }, + { + FieldElement{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684}, + FieldElement{-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518}, + FieldElement{-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}, + }, + { + FieldElement{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793}, + FieldElement{-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794}, + FieldElement{580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}, + }, + { + FieldElement{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921}, + FieldElement{13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518}, + FieldElement{2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}, + }, + { + FieldElement{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278}, + FieldElement{-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024}, + FieldElement{4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}, + }, + { + FieldElement{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783}, + FieldElement{27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717}, + FieldElement{6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}, + }, + { + FieldElement{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333}, + FieldElement{16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048}, + FieldElement{22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}, + }, + { + FieldElement{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760}, + FieldElement{-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757}, + FieldElement{-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}, + }, + }, + { + { + FieldElement{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468}, + FieldElement{3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184}, + FieldElement{10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}, + }, + { + FieldElement{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066}, + FieldElement{24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882}, + FieldElement{13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}, + }, + { + FieldElement{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101}, + FieldElement{29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279}, + FieldElement{-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}, + }, + { + FieldElement{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709}, + FieldElement{20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714}, + FieldElement{-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}, + }, + { + FieldElement{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464}, + FieldElement{12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847}, + FieldElement{13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}, + }, + { + FieldElement{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414}, + FieldElement{-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158}, + FieldElement{17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}, + }, + { + FieldElement{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415}, + FieldElement{-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459}, + FieldElement{-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}, + }, + { + FieldElement{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412}, + FieldElement{-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743}, + FieldElement{-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}, + }, + }, + { + { + FieldElement{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022}, + FieldElement{18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429}, + FieldElement{-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}, + }, + { + FieldElement{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861}, + FieldElement{10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000}, + FieldElement{-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}, + }, + { + FieldElement{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815}, + FieldElement{29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642}, + FieldElement{10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}, + }, + { + FieldElement{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574}, + FieldElement{-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742}, + FieldElement{-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}, + }, + { + FieldElement{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020}, + FieldElement{-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772}, + FieldElement{3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}, + }, + { + FieldElement{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953}, + FieldElement{-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218}, + FieldElement{-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}, + }, + { + FieldElement{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073}, + FieldElement{-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325}, + FieldElement{-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}, + }, + { + FieldElement{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870}, + FieldElement{-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863}, + FieldElement{-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}, + }, + }, + { + { + FieldElement{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267}, + FieldElement{-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663}, + FieldElement{22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}, + }, + { + FieldElement{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673}, + FieldElement{15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943}, + FieldElement{15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}, + }, + { + FieldElement{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238}, + FieldElement{11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064}, + FieldElement{14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}, + }, + { + FieldElement{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052}, + FieldElement{-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904}, + FieldElement{29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}, + }, + { + FieldElement{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979}, + FieldElement{-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841}, + FieldElement{10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}, + }, + { + FieldElement{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324}, + FieldElement{-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940}, + FieldElement{10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}, + }, + { + FieldElement{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184}, + FieldElement{14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114}, + FieldElement{30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}, + }, + { + FieldElement{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784}, + FieldElement{-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091}, + FieldElement{-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}, + }, + }, + { + { + FieldElement{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208}, + FieldElement{10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864}, + FieldElement{17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}, + }, + { + FieldElement{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233}, + FieldElement{26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212}, + FieldElement{-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}, + }, + { + FieldElement{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068}, + FieldElement{9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397}, + FieldElement{-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}, + }, + { + FieldElement{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889}, + FieldElement{32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038}, + FieldElement{14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}, + }, + { + FieldElement{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875}, + FieldElement{-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905}, + FieldElement{-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}, + }, + { + FieldElement{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818}, + FieldElement{27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714}, + FieldElement{10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}, + }, + { + FieldElement{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931}, + FieldElement{-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024}, + FieldElement{-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}, + }, + { + FieldElement{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204}, + FieldElement{20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817}, + FieldElement{27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}, + }, + }, + { + { + FieldElement{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504}, + FieldElement{-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768}, + FieldElement{-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}, + }, + { + FieldElement{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790}, + FieldElement{1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438}, + FieldElement{-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}, + }, + { + FieldElement{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971}, + FieldElement{31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905}, + FieldElement{29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}, + }, + { + FieldElement{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409}, + FieldElement{6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499}, + FieldElement{-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}, + }, + { + FieldElement{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664}, + FieldElement{-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324}, + FieldElement{-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}, + }, + { + FieldElement{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990}, + FieldElement{-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914}, + FieldElement{-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}, + }, + { + FieldElement{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257}, + FieldElement{-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433}, + FieldElement{-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}, + }, + { + FieldElement{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045}, + FieldElement{11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093}, + FieldElement{-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}, + }, + }, + { + { + FieldElement{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191}, + FieldElement{-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507}, + FieldElement{-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}, + }, + { + FieldElement{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018}, + FieldElement{-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109}, + FieldElement{-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}, + }, + { + FieldElement{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528}, + FieldElement{8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625}, + FieldElement{-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}, + }, + { + FieldElement{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033}, + FieldElement{27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866}, + FieldElement{21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}, + }, + { + FieldElement{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075}, + FieldElement{26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347}, + FieldElement{-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}, + }, + { + FieldElement{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165}, + FieldElement{-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588}, + FieldElement{-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}, + }, + { + FieldElement{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017}, + FieldElement{-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883}, + FieldElement{21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}, + }, + { + FieldElement{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043}, + FieldElement{29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663}, + FieldElement{-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}, + }, + }, + { + { + FieldElement{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860}, + FieldElement{2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466}, + FieldElement{-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}, + }, + { + FieldElement{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997}, + FieldElement{-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295}, + FieldElement{-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}, + }, + { + FieldElement{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385}, + FieldElement{18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109}, + FieldElement{2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}, + }, + { + FieldElement{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424}, + FieldElement{-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185}, + FieldElement{7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}, + }, + { + FieldElement{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325}, + FieldElement{10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593}, + FieldElement{696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}, + }, + { + FieldElement{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644}, + FieldElement{17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801}, + FieldElement{26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}, + }, + { + FieldElement{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884}, + FieldElement{-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577}, + FieldElement{-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}, + }, + { + FieldElement{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473}, + FieldElement{-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644}, + FieldElement{-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}, + }, + }, + { + { + FieldElement{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599}, + FieldElement{-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768}, + FieldElement{-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}, + }, + { + FieldElement{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328}, + FieldElement{-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369}, + FieldElement{20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}, + }, + { + FieldElement{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815}, + FieldElement{-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025}, + FieldElement{-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}, + }, + { + FieldElement{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448}, + FieldElement{6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981}, + FieldElement{30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}, + }, + { + FieldElement{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501}, + FieldElement{17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073}, + FieldElement{-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}, + }, + { + FieldElement{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845}, + FieldElement{-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211}, + FieldElement{18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}, + }, + { + FieldElement{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096}, + FieldElement{33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803}, + FieldElement{-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}, + }, + { + FieldElement{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965}, + FieldElement{-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505}, + FieldElement{18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}, + }, + }, + { + { + FieldElement{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782}, + FieldElement{5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900}, + FieldElement{-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}, + }, + { + FieldElement{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208}, + FieldElement{8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232}, + FieldElement{17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}, + }, + { + FieldElement{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271}, + FieldElement{-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326}, + FieldElement{-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}, + }, + { + FieldElement{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300}, + FieldElement{8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570}, + FieldElement{15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}, + }, + { + FieldElement{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994}, + FieldElement{-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913}, + FieldElement{31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}, + }, + { + FieldElement{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730}, + FieldElement{842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096}, + FieldElement{-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}, + }, + { + FieldElement{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411}, + FieldElement{-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905}, + FieldElement{-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}, + }, + { + FieldElement{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870}, + FieldElement{-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498}, + FieldElement{12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}, + }, + }, + { + { + FieldElement{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677}, + FieldElement{10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647}, + FieldElement{-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}, + }, + { + FieldElement{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468}, + FieldElement{21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375}, + FieldElement{-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}, + }, + { + FieldElement{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725}, + FieldElement{-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612}, + FieldElement{-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}, + }, + { + FieldElement{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944}, + FieldElement{30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928}, + FieldElement{9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}, + }, + { + FieldElement{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139}, + FieldElement{-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963}, + FieldElement{-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}, + }, + { + FieldElement{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734}, + FieldElement{-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680}, + FieldElement{-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}, + }, + { + FieldElement{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931}, + FieldElement{-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654}, + FieldElement{22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}, + }, + { + FieldElement{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180}, + FieldElement{-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684}, + FieldElement{-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}, + }, + }, + { + { + FieldElement{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501}, + FieldElement{-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413}, + FieldElement{6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}, + }, + { + FieldElement{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874}, + FieldElement{22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962}, + FieldElement{-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}, + }, + { + FieldElement{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152}, + FieldElement{9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063}, + FieldElement{7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}, + }, + { + FieldElement{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146}, + FieldElement{-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183}, + FieldElement{-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}, + }, + { + FieldElement{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421}, + FieldElement{-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622}, + FieldElement{-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}, + }, + { + FieldElement{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663}, + FieldElement{31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753}, + FieldElement{4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}, + }, + { + FieldElement{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862}, + FieldElement{-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118}, + FieldElement{26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}, + }, + { + FieldElement{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380}, + FieldElement{16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824}, + FieldElement{28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}, + }, + }, + { + { + FieldElement{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438}, + FieldElement{-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584}, + FieldElement{-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}, + }, + { + FieldElement{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471}, + FieldElement{18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610}, + FieldElement{19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}, + }, + { + FieldElement{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650}, + FieldElement{14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369}, + FieldElement{19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}, + }, + { + FieldElement{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462}, + FieldElement{-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793}, + FieldElement{-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}, + }, + { + FieldElement{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226}, + FieldElement{18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019}, + FieldElement{-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}, + }, + { + FieldElement{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171}, + FieldElement{-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132}, + FieldElement{-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}, + }, + { + FieldElement{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181}, + FieldElement{-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210}, + FieldElement{-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}, + }, + { + FieldElement{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935}, + FieldElement{24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105}, + FieldElement{-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}, + }, + }, + { + { + FieldElement{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852}, + FieldElement{5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581}, + FieldElement{-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}, + }, + { + FieldElement{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844}, + FieldElement{10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025}, + FieldElement{27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}, + }, + { + FieldElement{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068}, + FieldElement{4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192}, + FieldElement{-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}, + }, + { + FieldElement{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259}, + FieldElement{-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426}, + FieldElement{-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}, + }, + { + FieldElement{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305}, + FieldElement{13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832}, + FieldElement{28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}, + }, + { + FieldElement{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011}, + FieldElement{24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447}, + FieldElement{17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}, + }, + { + FieldElement{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245}, + FieldElement{-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859}, + FieldElement{28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}, + }, + { + FieldElement{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707}, + FieldElement{10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848}, + FieldElement{-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}, + }, + }, + { + { + FieldElement{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391}, + FieldElement{15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215}, + FieldElement{-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}, + }, + { + FieldElement{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713}, + FieldElement{21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849}, + FieldElement{-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}, + }, + { + FieldElement{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940}, + FieldElement{-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031}, + FieldElement{-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}, + }, + { + FieldElement{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243}, + FieldElement{-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116}, + FieldElement{-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}, + }, + { + FieldElement{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509}, + FieldElement{-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883}, + FieldElement{15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}, + }, + { + FieldElement{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660}, + FieldElement{4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273}, + FieldElement{-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}, + }, + { + FieldElement{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560}, + FieldElement{-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135}, + FieldElement{2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}, + }, + { + FieldElement{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739}, + FieldElement{18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756}, + FieldElement{-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}, + }, + }, + { + { + FieldElement{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347}, + FieldElement{-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028}, + FieldElement{21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}, + }, + { + FieldElement{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799}, + FieldElement{-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609}, + FieldElement{-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}, + }, + { + FieldElement{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989}, + FieldElement{-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523}, + FieldElement{4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}, + }, + { + FieldElement{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045}, + FieldElement{19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377}, + FieldElement{24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}, + }, + { + FieldElement{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016}, + FieldElement{510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426}, + FieldElement{18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}, + }, + { + FieldElement{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396}, + FieldElement{9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080}, + FieldElement{12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}, + }, + { + FieldElement{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275}, + FieldElement{11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074}, + FieldElement{20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}, + }, + { + FieldElement{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717}, + FieldElement{-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101}, + FieldElement{24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}, + }, + }, + { + { + FieldElement{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632}, + FieldElement{-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415}, + FieldElement{-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}, + }, + { + FieldElement{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876}, + FieldElement{22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625}, + FieldElement{-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}, + }, + { + FieldElement{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164}, + FieldElement{26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595}, + FieldElement{-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}, + }, + { + FieldElement{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858}, + FieldElement{15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193}, + FieldElement{8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}, + }, + { + FieldElement{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942}, + FieldElement{-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635}, + FieldElement{21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}, + }, + { + FieldElement{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935}, + FieldElement{-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415}, + FieldElement{-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}, + }, + { + FieldElement{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018}, + FieldElement{4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778}, + FieldElement{366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}, + }, + { + FieldElement{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385}, + FieldElement{18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503}, + FieldElement{476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}, + }, + }, + { + { + FieldElement{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056}, + FieldElement{-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838}, + FieldElement{24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}, + }, + { + FieldElement{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691}, + FieldElement{-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118}, + FieldElement{-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}, + }, + { + FieldElement{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269}, + FieldElement{-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904}, + FieldElement{-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}, + }, + { + FieldElement{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193}, + FieldElement{-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910}, + FieldElement{-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}, + }, + { + FieldElement{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667}, + FieldElement{25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481}, + FieldElement{-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}, + }, + { + FieldElement{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640}, + FieldElement{-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278}, + FieldElement{-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}, + }, + { + FieldElement{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272}, + FieldElement{17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012}, + FieldElement{-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}, + }, + { + FieldElement{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046}, + FieldElement{13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345}, + FieldElement{-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}, + }, + }, + { + { + FieldElement{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937}, + FieldElement{31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636}, + FieldElement{-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}, + }, + { + FieldElement{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429}, + FieldElement{-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576}, + FieldElement{31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}, + }, + { + FieldElement{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490}, + FieldElement{-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104}, + FieldElement{33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}, + }, + { + FieldElement{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275}, + FieldElement{-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511}, + FieldElement{22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}, + }, + { + FieldElement{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439}, + FieldElement{23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939}, + FieldElement{-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}, + }, + { + FieldElement{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310}, + FieldElement{3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608}, + FieldElement{-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}, + }, + { + FieldElement{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101}, + FieldElement{21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418}, + FieldElement{18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}, + }, + { + FieldElement{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356}, + FieldElement{9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996}, + FieldElement{-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}, + }, + }, + { + { + FieldElement{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728}, + FieldElement{-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658}, + FieldElement{-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}, + }, + { + FieldElement{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001}, + FieldElement{-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766}, + FieldElement{18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}, + }, + { + FieldElement{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458}, + FieldElement{-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628}, + FieldElement{-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}, + }, + { + FieldElement{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062}, + FieldElement{25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616}, + FieldElement{31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}, + }, + { + FieldElement{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383}, + FieldElement{-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814}, + FieldElement{-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}, + }, + { + FieldElement{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417}, + FieldElement{2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222}, + FieldElement{33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}, + }, + { + FieldElement{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597}, + FieldElement{23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970}, + FieldElement{1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}, + }, + { + FieldElement{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647}, + FieldElement{13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511}, + FieldElement{-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}, + }, + }, + { + { + FieldElement{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834}, + FieldElement{-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461}, + FieldElement{29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}, + }, + { + FieldElement{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516}, + FieldElement{-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547}, + FieldElement{-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}, + }, + { + FieldElement{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038}, + FieldElement{-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741}, + FieldElement{16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}, + }, + { + FieldElement{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747}, + FieldElement{-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323}, + FieldElement{31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}, + }, + { + FieldElement{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373}, + FieldElement{15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228}, + FieldElement{-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}, + }, + { + FieldElement{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399}, + FieldElement{11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831}, + FieldElement{-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}, + }, + { + FieldElement{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313}, + FieldElement{-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958}, + FieldElement{-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}, + }, + { + FieldElement{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743}, + FieldElement{29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684}, + FieldElement{-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}, + }, + }, +} diff --git a/vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go new file mode 100644 index 000000000..fd03c252a --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/ed25519/internal/edwards25519/edwards25519.go @@ -0,0 +1,1793 @@ +// 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. + +package edwards25519 + +import "encoding/binary" + +// This code is a port of the public domain, “ref10” implementation of ed25519 +// from SUPERCOP. + +// FieldElement represents an element of the field GF(2^255 - 19). An element +// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 +// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on +// context. +type FieldElement [10]int32 + +var zero FieldElement + +func FeZero(fe *FieldElement) { + copy(fe[:], zero[:]) +} + +func FeOne(fe *FieldElement) { + FeZero(fe) + fe[0] = 1 +} + +func FeAdd(dst, a, b *FieldElement) { + dst[0] = a[0] + b[0] + dst[1] = a[1] + b[1] + dst[2] = a[2] + b[2] + dst[3] = a[3] + b[3] + dst[4] = a[4] + b[4] + dst[5] = a[5] + b[5] + dst[6] = a[6] + b[6] + dst[7] = a[7] + b[7] + dst[8] = a[8] + b[8] + dst[9] = a[9] + b[9] +} + +func FeSub(dst, a, b *FieldElement) { + dst[0] = a[0] - b[0] + dst[1] = a[1] - b[1] + dst[2] = a[2] - b[2] + dst[3] = a[3] - b[3] + dst[4] = a[4] - b[4] + dst[5] = a[5] - b[5] + dst[6] = a[6] - b[6] + dst[7] = a[7] - b[7] + dst[8] = a[8] - b[8] + dst[9] = a[9] - b[9] +} + +func FeCopy(dst, src *FieldElement) { + copy(dst[:], src[:]) +} + +// Replace (f,g) with (g,g) if b == 1; +// replace (f,g) with (f,g) if b == 0. +// +// Preconditions: b in {0,1}. +func FeCMove(f, g *FieldElement, b int32) { + b = -b + f[0] ^= b & (f[0] ^ g[0]) + f[1] ^= b & (f[1] ^ g[1]) + f[2] ^= b & (f[2] ^ g[2]) + f[3] ^= b & (f[3] ^ g[3]) + f[4] ^= b & (f[4] ^ g[4]) + f[5] ^= b & (f[5] ^ g[5]) + f[6] ^= b & (f[6] ^ g[6]) + f[7] ^= b & (f[7] ^ g[7]) + f[8] ^= b & (f[8] ^ g[8]) + f[9] ^= b & (f[9] ^ g[9]) +} + +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +func load4(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + r |= int64(in[3]) << 24 + return r +} + +func FeFromBytes(dst *FieldElement, src *[32]byte) { + h0 := load4(src[:]) + h1 := load3(src[4:]) << 6 + h2 := load3(src[7:]) << 5 + h3 := load3(src[10:]) << 3 + h4 := load3(src[13:]) << 2 + h5 := load4(src[16:]) + h6 := load3(src[20:]) << 7 + h7 := load3(src[23:]) << 5 + h8 := load3(src[26:]) << 4 + h9 := (load3(src[29:]) & 8388607) << 2 + + FeCombine(dst, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +// FeToBytes marshals h to s. +// Preconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Write p=2^255-19; q=floor(h/p). +// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). +// +// Proof: +// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. +// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. +// +// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). +// Then 0> 25 + q = (h[0] + q) >> 26 + q = (h[1] + q) >> 25 + q = (h[2] + q) >> 26 + q = (h[3] + q) >> 25 + q = (h[4] + q) >> 26 + q = (h[5] + q) >> 25 + q = (h[6] + q) >> 26 + q = (h[7] + q) >> 25 + q = (h[8] + q) >> 26 + q = (h[9] + q) >> 25 + + // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. + h[0] += 19 * q + // Goal: Output h-2^255 q, which is between 0 and 2^255-20. + + carry[0] = h[0] >> 26 + h[1] += carry[0] + h[0] -= carry[0] << 26 + carry[1] = h[1] >> 25 + h[2] += carry[1] + h[1] -= carry[1] << 25 + carry[2] = h[2] >> 26 + h[3] += carry[2] + h[2] -= carry[2] << 26 + carry[3] = h[3] >> 25 + h[4] += carry[3] + h[3] -= carry[3] << 25 + carry[4] = h[4] >> 26 + h[5] += carry[4] + h[4] -= carry[4] << 26 + carry[5] = h[5] >> 25 + h[6] += carry[5] + h[5] -= carry[5] << 25 + carry[6] = h[6] >> 26 + h[7] += carry[6] + h[6] -= carry[6] << 26 + carry[7] = h[7] >> 25 + h[8] += carry[7] + h[7] -= carry[7] << 25 + carry[8] = h[8] >> 26 + h[9] += carry[8] + h[8] -= carry[8] << 26 + carry[9] = h[9] >> 25 + h[9] -= carry[9] << 25 + // h10 = carry9 + + // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; + // evidently 2^255 h10-2^255 q = 0. + // Goal: Output h[0]+...+2^230 h[9]. + + s[0] = byte(h[0] >> 0) + s[1] = byte(h[0] >> 8) + s[2] = byte(h[0] >> 16) + s[3] = byte((h[0] >> 24) | (h[1] << 2)) + s[4] = byte(h[1] >> 6) + s[5] = byte(h[1] >> 14) + s[6] = byte((h[1] >> 22) | (h[2] << 3)) + s[7] = byte(h[2] >> 5) + s[8] = byte(h[2] >> 13) + s[9] = byte((h[2] >> 21) | (h[3] << 5)) + s[10] = byte(h[3] >> 3) + s[11] = byte(h[3] >> 11) + s[12] = byte((h[3] >> 19) | (h[4] << 6)) + s[13] = byte(h[4] >> 2) + s[14] = byte(h[4] >> 10) + s[15] = byte(h[4] >> 18) + s[16] = byte(h[5] >> 0) + s[17] = byte(h[5] >> 8) + s[18] = byte(h[5] >> 16) + s[19] = byte((h[5] >> 24) | (h[6] << 1)) + s[20] = byte(h[6] >> 7) + s[21] = byte(h[6] >> 15) + s[22] = byte((h[6] >> 23) | (h[7] << 3)) + s[23] = byte(h[7] >> 5) + s[24] = byte(h[7] >> 13) + s[25] = byte((h[7] >> 21) | (h[8] << 4)) + s[26] = byte(h[8] >> 4) + s[27] = byte(h[8] >> 12) + s[28] = byte((h[8] >> 20) | (h[9] << 6)) + s[29] = byte(h[9] >> 2) + s[30] = byte(h[9] >> 10) + s[31] = byte(h[9] >> 18) +} + +func FeIsNegative(f *FieldElement) byte { + var s [32]byte + FeToBytes(&s, f) + return s[0] & 1 +} + +func FeIsNonZero(f *FieldElement) int32 { + var s [32]byte + FeToBytes(&s, f) + var x uint8 + for _, b := range s { + x |= b + } + x |= x >> 4 + x |= x >> 2 + x |= x >> 1 + return int32(x & 1) +} + +// FeNeg sets h = -f +// +// Preconditions: +// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func FeNeg(h, f *FieldElement) { + h[0] = -f[0] + h[1] = -f[1] + h[2] = -f[2] + h[3] = -f[3] + h[4] = -f[4] + h[5] = -f[5] + h[6] = -f[6] + h[7] = -f[7] + h[8] = -f[8] + h[9] = -f[9] +} + +func FeCombine(h *FieldElement, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { + var c0, c1, c2, c3, c4, c5, c6, c7, c8, c9 int64 + + /* + |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 + */ + + c0 = (h0 + (1 << 25)) >> 26 + h1 += c0 + h0 -= c0 << 26 + c4 = (h4 + (1 << 25)) >> 26 + h5 += c4 + h4 -= c4 << 26 + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.51*2^58 */ + /* |h5| <= 1.51*2^58 */ + + c1 = (h1 + (1 << 24)) >> 25 + h2 += c1 + h1 -= c1 << 25 + c5 = (h5 + (1 << 24)) >> 25 + h6 += c5 + h5 -= c5 << 25 + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.21*2^59 */ + /* |h6| <= 1.21*2^59 */ + + c2 = (h2 + (1 << 25)) >> 26 + h3 += c2 + h2 -= c2 << 26 + c6 = (h6 + (1 << 25)) >> 26 + h7 += c6 + h6 -= c6 << 26 + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.51*2^58 */ + /* |h7| <= 1.51*2^58 */ + + c3 = (h3 + (1 << 24)) >> 25 + h4 += c3 + h3 -= c3 << 25 + c7 = (h7 + (1 << 24)) >> 25 + h8 += c7 + h7 -= c7 << 25 + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.52*2^33 */ + /* |h8| <= 1.52*2^33 */ + + c4 = (h4 + (1 << 25)) >> 26 + h5 += c4 + h4 -= c4 << 26 + c8 = (h8 + (1 << 25)) >> 26 + h9 += c8 + h8 -= c8 << 26 + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.51*2^58 */ + + c9 = (h9 + (1 << 24)) >> 25 + h0 += c9 * 19 + h9 -= c9 << 25 + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.8*2^37 */ + + c0 = (h0 + (1 << 25)) >> 26 + h1 += c0 + h0 -= c0 << 26 + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// FeMul calculates h = f * g +// Can overlap h with f or g. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Notes on implementation strategy: +// +// Using schoolbook multiplication. +// Karatsuba would save a little in some cost models. +// +// Most multiplications by 2 and 19 are 32-bit precomputations; +// cheaper than 64-bit postcomputations. +// +// There is one remaining multiplication by 19 in the carry chain; +// one *19 precomputation can be merged into this, +// but the resulting data flow is considerably less clean. +// +// There are 12 carries below. +// 10 of them are 2-way parallelizable and vectorizable. +// Can get away with 11 carries, but then data flow is much deeper. +// +// With tighter constraints on inputs, can squeeze carries into int32. +func FeMul(h, f, g *FieldElement) { + f0 := int64(f[0]) + f1 := int64(f[1]) + f2 := int64(f[2]) + f3 := int64(f[3]) + f4 := int64(f[4]) + f5 := int64(f[5]) + f6 := int64(f[6]) + f7 := int64(f[7]) + f8 := int64(f[8]) + f9 := int64(f[9]) + + f1_2 := int64(2 * f[1]) + f3_2 := int64(2 * f[3]) + f5_2 := int64(2 * f[5]) + f7_2 := int64(2 * f[7]) + f9_2 := int64(2 * f[9]) + + g0 := int64(g[0]) + g1 := int64(g[1]) + g2 := int64(g[2]) + g3 := int64(g[3]) + g4 := int64(g[4]) + g5 := int64(g[5]) + g6 := int64(g[6]) + g7 := int64(g[7]) + g8 := int64(g[8]) + g9 := int64(g[9]) + + g1_19 := int64(19 * g[1]) /* 1.4*2^29 */ + g2_19 := int64(19 * g[2]) /* 1.4*2^30; still ok */ + g3_19 := int64(19 * g[3]) + g4_19 := int64(19 * g[4]) + g5_19 := int64(19 * g[5]) + g6_19 := int64(19 * g[6]) + g7_19 := int64(19 * g[7]) + g8_19 := int64(19 * g[8]) + g9_19 := int64(19 * g[9]) + + h0 := f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*g1_19 + h1 := f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19 + h2 := f0*g2 + f1_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*g3_19 + h3 := f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19 + h4 := f0*g4 + f1_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*g5_19 + h5 := f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19 + h6 := f0*g6 + f1_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*g7_19 + h7 := f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19 + h8 := f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19 + h9 := f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0 + + FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +func feSquare(f *FieldElement) (h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) { + f0 := int64(f[0]) + f1 := int64(f[1]) + f2 := int64(f[2]) + f3 := int64(f[3]) + f4 := int64(f[4]) + f5 := int64(f[5]) + f6 := int64(f[6]) + f7 := int64(f[7]) + f8 := int64(f[8]) + f9 := int64(f[9]) + f0_2 := int64(2 * f[0]) + f1_2 := int64(2 * f[1]) + f2_2 := int64(2 * f[2]) + f3_2 := int64(2 * f[3]) + f4_2 := int64(2 * f[4]) + f5_2 := int64(2 * f[5]) + f6_2 := int64(2 * f[6]) + f7_2 := int64(2 * f[7]) + f5_38 := 38 * f5 // 1.31*2^30 + f6_19 := 19 * f6 // 1.31*2^30 + f7_38 := 38 * f7 // 1.31*2^30 + f8_19 := 19 * f8 // 1.31*2^30 + f9_38 := 38 * f9 // 1.31*2^30 + + h0 = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38 + h1 = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19 + h2 = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19 + h3 = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38 + h4 = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38 + h5 = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19 + h6 = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19 + h7 = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38 + h8 = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38 + h9 = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5 + + return +} + +// FeSquare calculates h = f*f. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func FeSquare(h, f *FieldElement) { + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f) + FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +// FeSquare2 sets h = 2 * f * f +// +// Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +// See fe_mul.c for discussion of implementation strategy. +func FeSquare2(h, f *FieldElement) { + h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f) + + h0 += h0 + h1 += h1 + h2 += h2 + h3 += h3 + h4 += h4 + h5 += h5 + h6 += h6 + h7 += h7 + h8 += h8 + h9 += h9 + + FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9) +} + +func FeInvert(out, z *FieldElement) { + var t0, t1, t2, t3 FieldElement + var i int + + FeSquare(&t0, z) // 2^1 + FeSquare(&t1, &t0) // 2^2 + for i = 1; i < 2; i++ { // 2^3 + FeSquare(&t1, &t1) + } + FeMul(&t1, z, &t1) // 2^3 + 2^0 + FeMul(&t0, &t0, &t1) // 2^3 + 2^1 + 2^0 + FeSquare(&t2, &t0) // 2^4 + 2^2 + 2^1 + FeMul(&t1, &t1, &t2) // 2^4 + 2^3 + 2^2 + 2^1 + 2^0 + FeSquare(&t2, &t1) // 5,4,3,2,1 + for i = 1; i < 5; i++ { // 9,8,7,6,5 + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0 + FeSquare(&t2, &t1) // 10..1 + for i = 1; i < 10; i++ { // 19..10 + FeSquare(&t2, &t2) + } + FeMul(&t2, &t2, &t1) // 19..0 + FeSquare(&t3, &t2) // 20..1 + for i = 1; i < 20; i++ { // 39..20 + FeSquare(&t3, &t3) + } + FeMul(&t2, &t3, &t2) // 39..0 + FeSquare(&t2, &t2) // 40..1 + for i = 1; i < 10; i++ { // 49..10 + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) // 49..0 + FeSquare(&t2, &t1) // 50..1 + for i = 1; i < 50; i++ { // 99..50 + FeSquare(&t2, &t2) + } + FeMul(&t2, &t2, &t1) // 99..0 + FeSquare(&t3, &t2) // 100..1 + for i = 1; i < 100; i++ { // 199..100 + FeSquare(&t3, &t3) + } + FeMul(&t2, &t3, &t2) // 199..0 + FeSquare(&t2, &t2) // 200..1 + for i = 1; i < 50; i++ { // 249..50 + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) // 249..0 + FeSquare(&t1, &t1) // 250..1 + for i = 1; i < 5; i++ { // 254..5 + FeSquare(&t1, &t1) + } + FeMul(out, &t1, &t0) // 254..5,3,1,0 +} + +func fePow22523(out, z *FieldElement) { + var t0, t1, t2 FieldElement + var i int + + FeSquare(&t0, z) + for i = 1; i < 1; i++ { + FeSquare(&t0, &t0) + } + FeSquare(&t1, &t0) + for i = 1; i < 2; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t1, z, &t1) + FeMul(&t0, &t0, &t1) + FeSquare(&t0, &t0) + for i = 1; i < 1; i++ { + FeSquare(&t0, &t0) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t1, &t0) + for i = 1; i < 5; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t1, &t0) + for i = 1; i < 10; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t1, &t1, &t0) + FeSquare(&t2, &t1) + for i = 1; i < 20; i++ { + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) + FeSquare(&t1, &t1) + for i = 1; i < 10; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t1, &t0) + for i = 1; i < 50; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t1, &t1, &t0) + FeSquare(&t2, &t1) + for i = 1; i < 100; i++ { + FeSquare(&t2, &t2) + } + FeMul(&t1, &t2, &t1) + FeSquare(&t1, &t1) + for i = 1; i < 50; i++ { + FeSquare(&t1, &t1) + } + FeMul(&t0, &t1, &t0) + FeSquare(&t0, &t0) + for i = 1; i < 2; i++ { + FeSquare(&t0, &t0) + } + FeMul(out, &t0, z) +} + +// Group elements are members of the elliptic curve -x^2 + y^2 = 1 + d * x^2 * +// y^2 where d = -121665/121666. +// +// Several representations are used: +// ProjectiveGroupElement: (X:Y:Z) satisfying x=X/Z, y=Y/Z +// ExtendedGroupElement: (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT +// CompletedGroupElement: ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T +// PreComputedGroupElement: (y+x,y-x,2dxy) + +type ProjectiveGroupElement struct { + X, Y, Z FieldElement +} + +type ExtendedGroupElement struct { + X, Y, Z, T FieldElement +} + +type CompletedGroupElement struct { + X, Y, Z, T FieldElement +} + +type PreComputedGroupElement struct { + yPlusX, yMinusX, xy2d FieldElement +} + +type CachedGroupElement struct { + yPlusX, yMinusX, Z, T2d FieldElement +} + +func (p *ProjectiveGroupElement) Zero() { + FeZero(&p.X) + FeOne(&p.Y) + FeOne(&p.Z) +} + +func (p *ProjectiveGroupElement) Double(r *CompletedGroupElement) { + var t0 FieldElement + + FeSquare(&r.X, &p.X) + FeSquare(&r.Z, &p.Y) + FeSquare2(&r.T, &p.Z) + FeAdd(&r.Y, &p.X, &p.Y) + FeSquare(&t0, &r.Y) + FeAdd(&r.Y, &r.Z, &r.X) + FeSub(&r.Z, &r.Z, &r.X) + FeSub(&r.X, &t0, &r.Y) + FeSub(&r.T, &r.T, &r.Z) +} + +func (p *ProjectiveGroupElement) ToBytes(s *[32]byte) { + var recip, x, y FieldElement + + FeInvert(&recip, &p.Z) + FeMul(&x, &p.X, &recip) + FeMul(&y, &p.Y, &recip) + FeToBytes(s, &y) + s[31] ^= FeIsNegative(&x) << 7 +} + +func (p *ExtendedGroupElement) Zero() { + FeZero(&p.X) + FeOne(&p.Y) + FeOne(&p.Z) + FeZero(&p.T) +} + +func (p *ExtendedGroupElement) Double(r *CompletedGroupElement) { + var q ProjectiveGroupElement + p.ToProjective(&q) + q.Double(r) +} + +func (p *ExtendedGroupElement) ToCached(r *CachedGroupElement) { + FeAdd(&r.yPlusX, &p.Y, &p.X) + FeSub(&r.yMinusX, &p.Y, &p.X) + FeCopy(&r.Z, &p.Z) + FeMul(&r.T2d, &p.T, &d2) +} + +func (p *ExtendedGroupElement) ToProjective(r *ProjectiveGroupElement) { + FeCopy(&r.X, &p.X) + FeCopy(&r.Y, &p.Y) + FeCopy(&r.Z, &p.Z) +} + +func (p *ExtendedGroupElement) ToBytes(s *[32]byte) { + var recip, x, y FieldElement + + FeInvert(&recip, &p.Z) + FeMul(&x, &p.X, &recip) + FeMul(&y, &p.Y, &recip) + FeToBytes(s, &y) + s[31] ^= FeIsNegative(&x) << 7 +} + +func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool { + var u, v, v3, vxx, check FieldElement + + FeFromBytes(&p.Y, s) + FeOne(&p.Z) + FeSquare(&u, &p.Y) + FeMul(&v, &u, &d) + FeSub(&u, &u, &p.Z) // y = y^2-1 + FeAdd(&v, &v, &p.Z) // v = dy^2+1 + + FeSquare(&v3, &v) + FeMul(&v3, &v3, &v) // v3 = v^3 + FeSquare(&p.X, &v3) + FeMul(&p.X, &p.X, &v) + FeMul(&p.X, &p.X, &u) // x = uv^7 + + fePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8) + FeMul(&p.X, &p.X, &v3) + FeMul(&p.X, &p.X, &u) // x = uv^3(uv^7)^((q-5)/8) + + var tmpX, tmp2 [32]byte + + FeSquare(&vxx, &p.X) + FeMul(&vxx, &vxx, &v) + FeSub(&check, &vxx, &u) // vx^2-u + if FeIsNonZero(&check) == 1 { + FeAdd(&check, &vxx, &u) // vx^2+u + if FeIsNonZero(&check) == 1 { + return false + } + FeMul(&p.X, &p.X, &SqrtM1) + + FeToBytes(&tmpX, &p.X) + for i, v := range tmpX { + tmp2[31-i] = v + } + } + + if FeIsNegative(&p.X) != (s[31] >> 7) { + FeNeg(&p.X, &p.X) + } + + FeMul(&p.T, &p.X, &p.Y) + return true +} + +func (p *CompletedGroupElement) ToProjective(r *ProjectiveGroupElement) { + FeMul(&r.X, &p.X, &p.T) + FeMul(&r.Y, &p.Y, &p.Z) + FeMul(&r.Z, &p.Z, &p.T) +} + +func (p *CompletedGroupElement) ToExtended(r *ExtendedGroupElement) { + FeMul(&r.X, &p.X, &p.T) + FeMul(&r.Y, &p.Y, &p.Z) + FeMul(&r.Z, &p.Z, &p.T) + FeMul(&r.T, &p.X, &p.Y) +} + +func (p *PreComputedGroupElement) Zero() { + FeOne(&p.yPlusX) + FeOne(&p.yMinusX) + FeZero(&p.xy2d) +} + +func geAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yPlusX) + FeMul(&r.Y, &r.Y, &q.yMinusX) + FeMul(&r.T, &q.T2d, &p.T) + FeMul(&r.X, &p.Z, &q.Z) + FeAdd(&t0, &r.X, &r.X) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeAdd(&r.Z, &t0, &r.T) + FeSub(&r.T, &t0, &r.T) +} + +func geSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yMinusX) + FeMul(&r.Y, &r.Y, &q.yPlusX) + FeMul(&r.T, &q.T2d, &p.T) + FeMul(&r.X, &p.Z, &q.Z) + FeAdd(&t0, &r.X, &r.X) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeSub(&r.Z, &t0, &r.T) + FeAdd(&r.T, &t0, &r.T) +} + +func geMixedAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yPlusX) + FeMul(&r.Y, &r.Y, &q.yMinusX) + FeMul(&r.T, &q.xy2d, &p.T) + FeAdd(&t0, &p.Z, &p.Z) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeAdd(&r.Z, &t0, &r.T) + FeSub(&r.T, &t0, &r.T) +} + +func geMixedSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) { + var t0 FieldElement + + FeAdd(&r.X, &p.Y, &p.X) + FeSub(&r.Y, &p.Y, &p.X) + FeMul(&r.Z, &r.X, &q.yMinusX) + FeMul(&r.Y, &r.Y, &q.yPlusX) + FeMul(&r.T, &q.xy2d, &p.T) + FeAdd(&t0, &p.Z, &p.Z) + FeSub(&r.X, &r.Z, &r.Y) + FeAdd(&r.Y, &r.Z, &r.Y) + FeSub(&r.Z, &t0, &r.T) + FeAdd(&r.T, &t0, &r.T) +} + +func slide(r *[256]int8, a *[32]byte) { + for i := range r { + r[i] = int8(1 & (a[i>>3] >> uint(i&7))) + } + + for i := range r { + if r[i] != 0 { + for b := 1; b <= 6 && i+b < 256; b++ { + if r[i+b] != 0 { + if r[i]+(r[i+b]<= -15 { + r[i] -= r[i+b] << uint(b) + for k := i + b; k < 256; k++ { + if r[k] == 0 { + r[k] = 1 + break + } + r[k] = 0 + } + } else { + break + } + } + } + } + } +} + +// GeDoubleScalarMultVartime sets r = a*A + b*B +// where a = a[0]+256*a[1]+...+256^31 a[31]. +// and b = b[0]+256*b[1]+...+256^31 b[31]. +// B is the Ed25519 base point (x,4/5) with x positive. +func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *[32]byte, A *ExtendedGroupElement, b *[32]byte) { + var aSlide, bSlide [256]int8 + var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A + var t CompletedGroupElement + var u, A2 ExtendedGroupElement + var i int + + slide(&aSlide, a) + slide(&bSlide, b) + + A.ToCached(&Ai[0]) + A.Double(&t) + t.ToExtended(&A2) + + for i := 0; i < 7; i++ { + geAdd(&t, &A2, &Ai[i]) + t.ToExtended(&u) + u.ToCached(&Ai[i+1]) + } + + r.Zero() + + for i = 255; i >= 0; i-- { + if aSlide[i] != 0 || bSlide[i] != 0 { + break + } + } + + for ; i >= 0; i-- { + r.Double(&t) + + if aSlide[i] > 0 { + t.ToExtended(&u) + geAdd(&t, &u, &Ai[aSlide[i]/2]) + } else if aSlide[i] < 0 { + t.ToExtended(&u) + geSub(&t, &u, &Ai[(-aSlide[i])/2]) + } + + if bSlide[i] > 0 { + t.ToExtended(&u) + geMixedAdd(&t, &u, &bi[bSlide[i]/2]) + } else if bSlide[i] < 0 { + t.ToExtended(&u) + geMixedSub(&t, &u, &bi[(-bSlide[i])/2]) + } + + t.ToProjective(r) + } +} + +// equal returns 1 if b == c and 0 otherwise, assuming that b and c are +// non-negative. +func equal(b, c int32) int32 { + x := uint32(b ^ c) + x-- + return int32(x >> 31) +} + +// negative returns 1 if b < 0 and 0 otherwise. +func negative(b int32) int32 { + return (b >> 31) & 1 +} + +func PreComputedGroupElementCMove(t, u *PreComputedGroupElement, b int32) { + FeCMove(&t.yPlusX, &u.yPlusX, b) + FeCMove(&t.yMinusX, &u.yMinusX, b) + FeCMove(&t.xy2d, &u.xy2d, b) +} + +func selectPoint(t *PreComputedGroupElement, pos int32, b int32) { + var minusT PreComputedGroupElement + bNegative := negative(b) + bAbs := b - (((-bNegative) & b) << 1) + + t.Zero() + for i := int32(0); i < 8; i++ { + PreComputedGroupElementCMove(t, &base[pos][i], equal(bAbs, i+1)) + } + FeCopy(&minusT.yPlusX, &t.yMinusX) + FeCopy(&minusT.yMinusX, &t.yPlusX) + FeNeg(&minusT.xy2d, &t.xy2d) + PreComputedGroupElementCMove(t, &minusT, bNegative) +} + +// GeScalarMultBase computes h = a*B, where +// a = a[0]+256*a[1]+...+256^31 a[31] +// B is the Ed25519 base point (x,4/5) with x positive. +// +// Preconditions: +// a[31] <= 127 +func GeScalarMultBase(h *ExtendedGroupElement, a *[32]byte) { + var e [64]int8 + + for i, v := range a { + e[2*i] = int8(v & 15) + e[2*i+1] = int8((v >> 4) & 15) + } + + // each e[i] is between 0 and 15 and e[63] is between 0 and 7. + + carry := int8(0) + for i := 0; i < 63; i++ { + e[i] += carry + carry = (e[i] + 8) >> 4 + e[i] -= carry << 4 + } + e[63] += carry + // each e[i] is between -8 and 8. + + h.Zero() + var t PreComputedGroupElement + var r CompletedGroupElement + for i := int32(1); i < 64; i += 2 { + selectPoint(&t, i/2, int32(e[i])) + geMixedAdd(&r, h, &t) + r.ToExtended(h) + } + + var s ProjectiveGroupElement + + h.Double(&r) + r.ToProjective(&s) + s.Double(&r) + r.ToProjective(&s) + s.Double(&r) + r.ToProjective(&s) + s.Double(&r) + r.ToExtended(h) + + for i := int32(0); i < 64; i += 2 { + selectPoint(&t, i/2, int32(e[i])) + geMixedAdd(&r, h, &t) + r.ToExtended(h) + } +} + +// The scalars are GF(2^252 + 27742317777372353535851937790883648493). + +// Input: +// a[0]+256*a[1]+...+256^31*a[31] = a +// b[0]+256*b[1]+...+256^31*b[31] = b +// c[0]+256*c[1]+...+256^31*c[31] = c +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +func ScMulAdd(s, a, b, c *[32]byte) { + a0 := 2097151 & load3(a[:]) + a1 := 2097151 & (load4(a[2:]) >> 5) + a2 := 2097151 & (load3(a[5:]) >> 2) + a3 := 2097151 & (load4(a[7:]) >> 7) + a4 := 2097151 & (load4(a[10:]) >> 4) + a5 := 2097151 & (load3(a[13:]) >> 1) + a6 := 2097151 & (load4(a[15:]) >> 6) + a7 := 2097151 & (load3(a[18:]) >> 3) + a8 := 2097151 & load3(a[21:]) + a9 := 2097151 & (load4(a[23:]) >> 5) + a10 := 2097151 & (load3(a[26:]) >> 2) + a11 := (load4(a[28:]) >> 7) + b0 := 2097151 & load3(b[:]) + b1 := 2097151 & (load4(b[2:]) >> 5) + b2 := 2097151 & (load3(b[5:]) >> 2) + b3 := 2097151 & (load4(b[7:]) >> 7) + b4 := 2097151 & (load4(b[10:]) >> 4) + b5 := 2097151 & (load3(b[13:]) >> 1) + b6 := 2097151 & (load4(b[15:]) >> 6) + b7 := 2097151 & (load3(b[18:]) >> 3) + b8 := 2097151 & load3(b[21:]) + b9 := 2097151 & (load4(b[23:]) >> 5) + b10 := 2097151 & (load3(b[26:]) >> 2) + b11 := (load4(b[28:]) >> 7) + c0 := 2097151 & load3(c[:]) + c1 := 2097151 & (load4(c[2:]) >> 5) + c2 := 2097151 & (load3(c[5:]) >> 2) + c3 := 2097151 & (load4(c[7:]) >> 7) + c4 := 2097151 & (load4(c[10:]) >> 4) + c5 := 2097151 & (load3(c[13:]) >> 1) + c6 := 2097151 & (load4(c[15:]) >> 6) + c7 := 2097151 & (load3(c[18:]) >> 3) + c8 := 2097151 & load3(c[21:]) + c9 := 2097151 & (load4(c[23:]) >> 5) + c10 := 2097151 & (load3(c[26:]) >> 2) + c11 := (load4(c[28:]) >> 7) + var carry [23]int64 + + s0 := c0 + a0*b0 + s1 := c1 + a0*b1 + a1*b0 + s2 := c2 + a0*b2 + a1*b1 + a2*b0 + s3 := c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0 + s4 := c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0 + s5 := c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0 + s6 := c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0 + s7 := c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0 + s8 := c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0 + s9 := c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0 + s10 := c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0 + s11 := c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0 + s12 := a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1 + s13 := a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2 + s14 := a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3 + s15 := a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4 + s16 := a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5 + s17 := a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6 + s18 := a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7 + s19 := a8*b11 + a9*b10 + a10*b9 + a11*b8 + s20 := a9*b11 + a10*b10 + a11*b9 + s21 := a10*b11 + a11*b10 + s22 := a11 * b11 + s23 := int64(0) + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + carry[18] = (s18 + (1 << 20)) >> 21 + s19 += carry[18] + s18 -= carry[18] << 21 + carry[20] = (s20 + (1 << 20)) >> 21 + s21 += carry[20] + s20 -= carry[20] << 21 + carry[22] = (s22 + (1 << 20)) >> 21 + s23 += carry[22] + s22 -= carry[22] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + carry[17] = (s17 + (1 << 20)) >> 21 + s18 += carry[17] + s17 -= carry[17] << 21 + carry[19] = (s19 + (1 << 20)) >> 21 + s20 += carry[19] + s19 -= carry[19] << 21 + carry[21] = (s21 + (1 << 20)) >> 21 + s22 += carry[21] + s21 -= carry[21] << 21 + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + s[0] = byte(s0 >> 0) + s[1] = byte(s0 >> 8) + s[2] = byte((s0 >> 16) | (s1 << 5)) + s[3] = byte(s1 >> 3) + s[4] = byte(s1 >> 11) + s[5] = byte((s1 >> 19) | (s2 << 2)) + s[6] = byte(s2 >> 6) + s[7] = byte((s2 >> 14) | (s3 << 7)) + s[8] = byte(s3 >> 1) + s[9] = byte(s3 >> 9) + s[10] = byte((s3 >> 17) | (s4 << 4)) + s[11] = byte(s4 >> 4) + s[12] = byte(s4 >> 12) + s[13] = byte((s4 >> 20) | (s5 << 1)) + s[14] = byte(s5 >> 7) + s[15] = byte((s5 >> 15) | (s6 << 6)) + s[16] = byte(s6 >> 2) + s[17] = byte(s6 >> 10) + s[18] = byte((s6 >> 18) | (s7 << 3)) + s[19] = byte(s7 >> 5) + s[20] = byte(s7 >> 13) + s[21] = byte(s8 >> 0) + s[22] = byte(s8 >> 8) + s[23] = byte((s8 >> 16) | (s9 << 5)) + s[24] = byte(s9 >> 3) + s[25] = byte(s9 >> 11) + s[26] = byte((s9 >> 19) | (s10 << 2)) + s[27] = byte(s10 >> 6) + s[28] = byte((s10 >> 14) | (s11 << 7)) + s[29] = byte(s11 >> 1) + s[30] = byte(s11 >> 9) + s[31] = byte(s11 >> 17) +} + +// Input: +// s[0]+256*s[1]+...+256^63*s[63] = s +// +// Output: +// s[0]+256*s[1]+...+256^31*s[31] = s mod l +// where l = 2^252 + 27742317777372353535851937790883648493. +func ScReduce(out *[32]byte, s *[64]byte) { + s0 := 2097151 & load3(s[:]) + s1 := 2097151 & (load4(s[2:]) >> 5) + s2 := 2097151 & (load3(s[5:]) >> 2) + s3 := 2097151 & (load4(s[7:]) >> 7) + s4 := 2097151 & (load4(s[10:]) >> 4) + s5 := 2097151 & (load3(s[13:]) >> 1) + s6 := 2097151 & (load4(s[15:]) >> 6) + s7 := 2097151 & (load3(s[18:]) >> 3) + s8 := 2097151 & load3(s[21:]) + s9 := 2097151 & (load4(s[23:]) >> 5) + s10 := 2097151 & (load3(s[26:]) >> 2) + s11 := 2097151 & (load4(s[28:]) >> 7) + s12 := 2097151 & (load4(s[31:]) >> 4) + s13 := 2097151 & (load3(s[34:]) >> 1) + s14 := 2097151 & (load4(s[36:]) >> 6) + s15 := 2097151 & (load3(s[39:]) >> 3) + s16 := 2097151 & load3(s[42:]) + s17 := 2097151 & (load4(s[44:]) >> 5) + s18 := 2097151 & (load3(s[47:]) >> 2) + s19 := 2097151 & (load4(s[49:]) >> 7) + s20 := 2097151 & (load4(s[52:]) >> 4) + s21 := 2097151 & (load3(s[55:]) >> 1) + s22 := 2097151 & (load4(s[57:]) >> 6) + s23 := (load4(s[60:]) >> 3) + + s11 += s23 * 666643 + s12 += s23 * 470296 + s13 += s23 * 654183 + s14 -= s23 * 997805 + s15 += s23 * 136657 + s16 -= s23 * 683901 + s23 = 0 + + s10 += s22 * 666643 + s11 += s22 * 470296 + s12 += s22 * 654183 + s13 -= s22 * 997805 + s14 += s22 * 136657 + s15 -= s22 * 683901 + s22 = 0 + + s9 += s21 * 666643 + s10 += s21 * 470296 + s11 += s21 * 654183 + s12 -= s21 * 997805 + s13 += s21 * 136657 + s14 -= s21 * 683901 + s21 = 0 + + s8 += s20 * 666643 + s9 += s20 * 470296 + s10 += s20 * 654183 + s11 -= s20 * 997805 + s12 += s20 * 136657 + s13 -= s20 * 683901 + s20 = 0 + + s7 += s19 * 666643 + s8 += s19 * 470296 + s9 += s19 * 654183 + s10 -= s19 * 997805 + s11 += s19 * 136657 + s12 -= s19 * 683901 + s19 = 0 + + s6 += s18 * 666643 + s7 += s18 * 470296 + s8 += s18 * 654183 + s9 -= s18 * 997805 + s10 += s18 * 136657 + s11 -= s18 * 683901 + s18 = 0 + + var carry [17]int64 + + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[12] = (s12 + (1 << 20)) >> 21 + s13 += carry[12] + s12 -= carry[12] << 21 + carry[14] = (s14 + (1 << 20)) >> 21 + s15 += carry[14] + s14 -= carry[14] << 21 + carry[16] = (s16 + (1 << 20)) >> 21 + s17 += carry[16] + s16 -= carry[16] << 21 + + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + carry[13] = (s13 + (1 << 20)) >> 21 + s14 += carry[13] + s13 -= carry[13] << 21 + carry[15] = (s15 + (1 << 20)) >> 21 + s16 += carry[15] + s15 -= carry[15] << 21 + + s5 += s17 * 666643 + s6 += s17 * 470296 + s7 += s17 * 654183 + s8 -= s17 * 997805 + s9 += s17 * 136657 + s10 -= s17 * 683901 + s17 = 0 + + s4 += s16 * 666643 + s5 += s16 * 470296 + s6 += s16 * 654183 + s7 -= s16 * 997805 + s8 += s16 * 136657 + s9 -= s16 * 683901 + s16 = 0 + + s3 += s15 * 666643 + s4 += s15 * 470296 + s5 += s15 * 654183 + s6 -= s15 * 997805 + s7 += s15 * 136657 + s8 -= s15 * 683901 + s15 = 0 + + s2 += s14 * 666643 + s3 += s14 * 470296 + s4 += s14 * 654183 + s5 -= s14 * 997805 + s6 += s14 * 136657 + s7 -= s14 * 683901 + s14 = 0 + + s1 += s13 * 666643 + s2 += s13 * 470296 + s3 += s13 * 654183 + s4 -= s13 * 997805 + s5 += s13 * 136657 + s6 -= s13 * 683901 + s13 = 0 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = (s0 + (1 << 20)) >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[2] = (s2 + (1 << 20)) >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[4] = (s4 + (1 << 20)) >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[6] = (s6 + (1 << 20)) >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[8] = (s8 + (1 << 20)) >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[10] = (s10 + (1 << 20)) >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + carry[1] = (s1 + (1 << 20)) >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[3] = (s3 + (1 << 20)) >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[5] = (s5 + (1 << 20)) >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[7] = (s7 + (1 << 20)) >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[9] = (s9 + (1 << 20)) >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[11] = (s11 + (1 << 20)) >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + carry[11] = s11 >> 21 + s12 += carry[11] + s11 -= carry[11] << 21 + + s0 += s12 * 666643 + s1 += s12 * 470296 + s2 += s12 * 654183 + s3 -= s12 * 997805 + s4 += s12 * 136657 + s5 -= s12 * 683901 + s12 = 0 + + carry[0] = s0 >> 21 + s1 += carry[0] + s0 -= carry[0] << 21 + carry[1] = s1 >> 21 + s2 += carry[1] + s1 -= carry[1] << 21 + carry[2] = s2 >> 21 + s3 += carry[2] + s2 -= carry[2] << 21 + carry[3] = s3 >> 21 + s4 += carry[3] + s3 -= carry[3] << 21 + carry[4] = s4 >> 21 + s5 += carry[4] + s4 -= carry[4] << 21 + carry[5] = s5 >> 21 + s6 += carry[5] + s5 -= carry[5] << 21 + carry[6] = s6 >> 21 + s7 += carry[6] + s6 -= carry[6] << 21 + carry[7] = s7 >> 21 + s8 += carry[7] + s7 -= carry[7] << 21 + carry[8] = s8 >> 21 + s9 += carry[8] + s8 -= carry[8] << 21 + carry[9] = s9 >> 21 + s10 += carry[9] + s9 -= carry[9] << 21 + carry[10] = s10 >> 21 + s11 += carry[10] + s10 -= carry[10] << 21 + + out[0] = byte(s0 >> 0) + out[1] = byte(s0 >> 8) + out[2] = byte((s0 >> 16) | (s1 << 5)) + out[3] = byte(s1 >> 3) + out[4] = byte(s1 >> 11) + out[5] = byte((s1 >> 19) | (s2 << 2)) + out[6] = byte(s2 >> 6) + out[7] = byte((s2 >> 14) | (s3 << 7)) + out[8] = byte(s3 >> 1) + out[9] = byte(s3 >> 9) + out[10] = byte((s3 >> 17) | (s4 << 4)) + out[11] = byte(s4 >> 4) + out[12] = byte(s4 >> 12) + out[13] = byte((s4 >> 20) | (s5 << 1)) + out[14] = byte(s5 >> 7) + out[15] = byte((s5 >> 15) | (s6 << 6)) + out[16] = byte(s6 >> 2) + out[17] = byte(s6 >> 10) + out[18] = byte((s6 >> 18) | (s7 << 3)) + out[19] = byte(s7 >> 5) + out[20] = byte(s7 >> 13) + out[21] = byte(s8 >> 0) + out[22] = byte(s8 >> 8) + out[23] = byte((s8 >> 16) | (s9 << 5)) + out[24] = byte(s9 >> 3) + out[25] = byte(s9 >> 11) + out[26] = byte((s9 >> 19) | (s10 << 2)) + out[27] = byte(s10 >> 6) + out[28] = byte((s10 >> 14) | (s11 << 7)) + out[29] = byte(s11 >> 1) + out[30] = byte(s11 >> 9) + out[31] = byte(s11 >> 17) +} + +// order is the order of Curve25519 in little-endian form. +var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000} + +// ScMinimal returns true if the given scalar is less than the order of the +// curve. +func ScMinimal(scalar *[32]byte) bool { + for i := 3; ; i-- { + v := binary.LittleEndian.Uint64(scalar[i*8:]) + if v > order[i] { + return false + } else if v < order[i] { + break + } else if i == 0 { + return false + } + } + + return true +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/armor/armor.go b/vendor/github.com/keybase/go-crypto/openpgp/armor/armor.go new file mode 100644 index 000000000..b65b58bcb --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/armor/armor.go @@ -0,0 +1,253 @@ +// Copyright 2010 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 armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is +// very similar to PEM except that it has an additional CRC checksum. +package armor // import "github.com/keybase/go-crypto/openpgp/armor" + +import ( + "bufio" + "bytes" + "encoding/base64" + "io" + "strings" + "unicode" + + "github.com/keybase/go-crypto/openpgp/errors" +) + +// A Block represents an OpenPGP armored structure. +// +// The encoded form is: +// -----BEGIN Type----- +// Headers +// +// base64-encoded Bytes +// '=' base64 encoded checksum +// -----END Type----- +// where Headers is a possibly empty sequence of Key: Value lines. +// +// Since the armored data can be very large, this package presents a streaming +// interface. +type Block struct { + Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE"). + Header map[string]string // Optional headers. + Body io.Reader // A Reader from which the contents can be read + lReader lineReader + oReader openpgpReader +} + +var ArmorCorrupt error = errors.StructuralError("armor invalid") + +const crc24Init = 0xb704ce +const crc24Poly = 0x1864cfb +const crc24Mask = 0xffffff + +// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1 +func crc24(crc uint32, d []byte) uint32 { + for _, b := range d { + crc ^= uint32(b) << 16 + for i := 0; i < 8; i++ { + crc <<= 1 + if crc&0x1000000 != 0 { + crc ^= crc24Poly + } + } + } + return crc +} + +var armorStart = []byte("-----BEGIN ") +var armorEnd = []byte("-----END ") +var armorEndOfLine = []byte("-----") + +// lineReader wraps a line based reader. It watches for the end of an armor +// block and records the expected CRC value. +type lineReader struct { + in *bufio.Reader + buf []byte + eof bool + crc *uint32 +} + +// ourIsSpace checks if a rune is either space according to unicode +// package, or ZeroWidthSpace (which is not a space according to +// unicode module). Used to trim lines during header reading. +func ourIsSpace(r rune) bool { + return r == '\u200b' || unicode.IsSpace(r) +} + +func (l *lineReader) Read(p []byte) (n int, err error) { + if l.eof { + return 0, io.EOF + } + + if len(l.buf) > 0 { + n = copy(p, l.buf) + l.buf = l.buf[n:] + return + } + + line, _, err := l.in.ReadLine() + if err != nil { + return + } + + // Entry-level cleanup, just trim spaces. + line = bytes.TrimFunc(line, ourIsSpace) + + if len(line) == 5 && line[0] == '=' { + // This is the checksum line + var expectedBytes [3]byte + var m int + m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:]) + if m != 3 || err != nil { + return + } + crc := uint32(expectedBytes[0])<<16 | + uint32(expectedBytes[1])<<8 | + uint32(expectedBytes[2]) + l.crc = &crc + + for { + line, _, err = l.in.ReadLine() + if err == io.EOF { + break + } + if err != nil { + return + } + if len(strings.TrimSpace(string(line))) > 0 { + break + } + } + if !bytes.HasPrefix(line, armorEnd) { + return 0, ArmorCorrupt + } + + l.eof = true + return 0, io.EOF + } + + if bytes.HasPrefix(line, armorEnd) { + // Unexpected ending, there was no checksum. + l.eof = true + l.crc = nil + return 0, io.EOF + } + + // Clean-up line from whitespace to pass it further (to base64 + // decoder). This is done after test for CRC and test for + // armorEnd. Keys that have whitespace in CRC will have CRC + // treated as part of the payload and probably fail in base64 + // reading. + line = bytes.Map(func(r rune) rune { + if ourIsSpace(r) { + return -1 + } + return r + }, line) + + n = copy(p, line) + bytesToSave := len(line) - n + if bytesToSave > 0 { + if cap(l.buf) < bytesToSave { + l.buf = make([]byte, 0, bytesToSave) + } + l.buf = l.buf[0:bytesToSave] + copy(l.buf, line[n:]) + } + + return +} + +// openpgpReader passes Read calls to the underlying base64 decoder, but keeps +// a running CRC of the resulting data and checks the CRC against the value +// found by the lineReader at EOF. +type openpgpReader struct { + lReader *lineReader + b64Reader io.Reader + currentCRC uint32 +} + +func (r *openpgpReader) Read(p []byte) (n int, err error) { + n, err = r.b64Reader.Read(p) + r.currentCRC = crc24(r.currentCRC, p[:n]) + + if err == io.EOF { + if r.lReader.crc != nil && *r.lReader.crc != uint32(r.currentCRC&crc24Mask) { + return 0, ArmorCorrupt + } + } + + return +} + +// Decode reads a PGP armored block from the given Reader. It will ignore +// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The +// given Reader is not usable after calling this function: an arbitrary amount +// of data may have been read past the end of the block. +func Decode(in io.Reader) (p *Block, err error) { + r := bufio.NewReaderSize(in, 100) + var line []byte + ignoreNext := false + +TryNextBlock: + p = nil + + // Skip leading garbage + for { + ignoreThis := ignoreNext + line, ignoreNext, err = r.ReadLine() + if err != nil { + return + } + if ignoreNext || ignoreThis { + continue + } + line = bytes.TrimSpace(line) + if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) { + break + } + } + + p = new(Block) + p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)]) + p.Header = make(map[string]string) + nextIsContinuation := false + var lastKey string + + // Read headers + for { + isContinuation := nextIsContinuation + line, nextIsContinuation, err = r.ReadLine() + if err != nil { + p = nil + return + } + if isContinuation { + p.Header[lastKey] += string(line) + continue + } + line = bytes.TrimFunc(line, ourIsSpace) + if len(line) == 0 { + break + } + + i := bytes.Index(line, []byte(": ")) + if i == -1 { + goto TryNextBlock + } + lastKey = string(line[:i]) + p.Header[lastKey] = string(line[i+2:]) + } + + p.lReader.in = r + p.oReader.currentCRC = crc24Init + p.oReader.lReader = &p.lReader + p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader) + p.Body = &p.oReader + + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/armor/encode.go b/vendor/github.com/keybase/go-crypto/openpgp/armor/encode.go new file mode 100644 index 000000000..075a1978e --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/armor/encode.go @@ -0,0 +1,160 @@ +// Copyright 2010 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 armor + +import ( + "encoding/base64" + "io" +) + +var armorHeaderSep = []byte(": ") +var blockEnd = []byte("\n=") +var newline = []byte("\n") +var armorEndOfLineOut = []byte("-----\n") + +// writeSlices writes its arguments to the given Writer. +func writeSlices(out io.Writer, slices ...[]byte) (err error) { + for _, s := range slices { + _, err = out.Write(s) + if err != nil { + return err + } + } + return +} + +// lineBreaker breaks data across several lines, all of the same byte length +// (except possibly the last). Lines are broken with a single '\n'. +type lineBreaker struct { + lineLength int + line []byte + used int + out io.Writer + haveWritten bool +} + +func newLineBreaker(out io.Writer, lineLength int) *lineBreaker { + return &lineBreaker{ + lineLength: lineLength, + line: make([]byte, lineLength), + used: 0, + out: out, + } +} + +func (l *lineBreaker) Write(b []byte) (n int, err error) { + n = len(b) + + if n == 0 { + return + } + + if l.used == 0 && l.haveWritten { + _, err = l.out.Write([]byte{'\n'}) + if err != nil { + return + } + } + + if l.used+len(b) < l.lineLength { + l.used += copy(l.line[l.used:], b) + return + } + + l.haveWritten = true + _, err = l.out.Write(l.line[0:l.used]) + if err != nil { + return + } + excess := l.lineLength - l.used + l.used = 0 + + _, err = l.out.Write(b[0:excess]) + if err != nil { + return + } + + _, err = l.Write(b[excess:]) + return +} + +func (l *lineBreaker) Close() (err error) { + if l.used > 0 { + _, err = l.out.Write(l.line[0:l.used]) + if err != nil { + return + } + } + + return +} + +// encoding keeps track of a running CRC24 over the data which has been written +// to it and outputs a OpenPGP checksum when closed, followed by an armor +// trailer. +// +// It's built into a stack of io.Writers: +// encoding -> base64 encoder -> lineBreaker -> out +type encoding struct { + out io.Writer + breaker *lineBreaker + b64 io.WriteCloser + crc uint32 + blockType []byte +} + +func (e *encoding) Write(data []byte) (n int, err error) { + e.crc = crc24(e.crc, data) + return e.b64.Write(data) +} + +func (e *encoding) Close() (err error) { + err = e.b64.Close() + if err != nil { + return + } + e.breaker.Close() + + var checksumBytes [3]byte + checksumBytes[0] = byte(e.crc >> 16) + checksumBytes[1] = byte(e.crc >> 8) + checksumBytes[2] = byte(e.crc) + + var b64ChecksumBytes [4]byte + base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:]) + + return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine, []byte{'\n'}) +} + +// Encode returns a WriteCloser which will encode the data written to it in +// OpenPGP armor. +func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) { + bType := []byte(blockType) + err = writeSlices(out, armorStart, bType, armorEndOfLineOut) + if err != nil { + return + } + + for k, v := range headers { + err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline) + if err != nil { + return + } + } + + _, err = out.Write(newline) + if err != nil { + return + } + + e := &encoding{ + out: out, + breaker: newLineBreaker(out, 64), + crc: crc24Init, + blockType: bType, + } + e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker) + return e, nil +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/canonical_text.go b/vendor/github.com/keybase/go-crypto/openpgp/canonical_text.go new file mode 100644 index 000000000..e601e389f --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/canonical_text.go @@ -0,0 +1,59 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package openpgp + +import "hash" + +// NewCanonicalTextHash reformats text written to it into the canonical +// form and then applies the hash h. See RFC 4880, section 5.2.1. +func NewCanonicalTextHash(h hash.Hash) hash.Hash { + return &canonicalTextHash{h, 0} +} + +type canonicalTextHash struct { + h hash.Hash + s int +} + +var newline = []byte{'\r', '\n'} + +func (cth *canonicalTextHash) Write(buf []byte) (int, error) { + start := 0 + + for i, c := range buf { + switch cth.s { + case 0: + if c == '\r' { + cth.s = 1 + } else if c == '\n' { + cth.h.Write(buf[start:i]) + cth.h.Write(newline) + start = i + 1 + } + case 1: + cth.s = 0 + } + } + + cth.h.Write(buf[start:]) + return len(buf), nil +} + +func (cth *canonicalTextHash) Sum(in []byte) []byte { + return cth.h.Sum(in) +} + +func (cth *canonicalTextHash) Reset() { + cth.h.Reset() + cth.s = 0 +} + +func (cth *canonicalTextHash) Size() int { + return cth.h.Size() +} + +func (cth *canonicalTextHash) BlockSize() int { + return cth.h.BlockSize() +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/ecdh/ecdh.go b/vendor/github.com/keybase/go-crypto/openpgp/ecdh/ecdh.go new file mode 100644 index 000000000..64c18d0b3 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/ecdh/ecdh.go @@ -0,0 +1,282 @@ +package ecdh + +import ( + "bytes" + "crypto" + "crypto/aes" + "crypto/elliptic" + "encoding/binary" + "errors" + "github.com/keybase/go-crypto/curve25519" + "io" + "math/big" +) + +type PublicKey struct { + elliptic.Curve + X, Y *big.Int +} + +type PrivateKey struct { + PublicKey + X *big.Int +} + +// KDF implements Key Derivation Function as described in +// https://tools.ietf.org/html/rfc6637#section-7 +func (e *PublicKey) KDF(S []byte, kdfParams []byte, hash crypto.Hash) []byte { + sLen := (e.Curve.Params().P.BitLen() + 7) / 8 + buf := new(bytes.Buffer) + buf.Write([]byte{0, 0, 0, 1}) + if sLen > len(S) { + // zero-pad the S. If we got invalid S (bigger than curve's + // P), we are going to produce invalid key. Garbage in, + // garbage out. + buf.Write(make([]byte, sLen-len(S))) + } + buf.Write(S) + buf.Write(kdfParams) + + hashw := hash.New() + + hashw.Write(buf.Bytes()) + key := hashw.Sum(nil) + + return key +} + +// AESKeyUnwrap implements RFC 3394 Key Unwrapping. See +// http://tools.ietf.org/html/rfc3394#section-2.2.1 +// Note: The second described algorithm ("index-based") is implemented +// here. +func AESKeyUnwrap(key, cipherText []byte) ([]byte, error) { + if len(cipherText)%8 != 0 { + return nil, errors.New("cipherText must by a multiple of 64 bits") + } + + cipher, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + nblocks := len(cipherText)/8 - 1 + + // 1) Initialize variables. + // - Set A = C[0] + var A [aes.BlockSize]byte + copy(A[:8], cipherText[:8]) + + // For i = 1 to n + // Set R[i] = C[i] + R := make([]byte, len(cipherText)-8) + copy(R, cipherText[8:]) + + // 2) Compute intermediate values. + for j := 5; j >= 0; j-- { + for i := nblocks - 1; i >= 0; i-- { + // B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + // A = MSB(64, B) + t := uint64(nblocks*j + i + 1) + At := binary.BigEndian.Uint64(A[:8]) ^ t + binary.BigEndian.PutUint64(A[:8], At) + + copy(A[8:], R[i*8:i*8+8]) + cipher.Decrypt(A[:], A[:]) + + // R[i] = LSB(B, 64) + copy(R[i*8:i*8+8], A[8:]) + } + } + + // 3) Output results. + // If A is an appropriate initial value (see 2.2.3), + for i := 0; i < 8; i++ { + if A[i] != 0xA6 { + return nil, errors.New("Failed to unwrap key (A is not IV)") + } + } + + return R, nil +} + +// AESKeyWrap implements RFC 3394 Key Wrapping. See +// https://tools.ietf.org/html/rfc3394#section-2.2.2 +// Note: The second described algorithm ("index-based") is implemented +// here. +func AESKeyWrap(key, plainText []byte) ([]byte, error) { + if len(plainText)%8 != 0 { + return nil, errors.New("plainText must be a multiple of 64 bits") + } + + cipher, err := aes.NewCipher(key) // NewCipher checks key size + if err != nil { + return nil, err + } + + nblocks := len(plainText) / 8 + + // 1) Initialize variables. + var A [aes.BlockSize]byte + // Section 2.2.3.1 -- Initial Value + // http://tools.ietf.org/html/rfc3394#section-2.2.3.1 + for i := 0; i < 8; i++ { + A[i] = 0xA6 + } + + // For i = 1 to n + // Set R[i] = P[i] + R := make([]byte, len(plainText)) + copy(R, plainText) + + // 2) Calculate intermediate values. + for j := 0; j <= 5; j++ { + for i := 0; i < nblocks; i++ { + // B = AES(K, A | R[i]) + copy(A[8:], R[i*8:i*8+8]) + cipher.Encrypt(A[:], A[:]) + + // (Assume B = A) + // A = MSB(64, B) ^ t where t = (n*j)+1 + t := uint64(j*nblocks + i + 1) + At := binary.BigEndian.Uint64(A[:8]) ^ t + binary.BigEndian.PutUint64(A[:8], At) + + // R[i] = LSB(64, B) + copy(R[i*8:i*8+8], A[8:]) + } + } + + // 3) Output results. + // Set C[0] = A + // For i = 1 to n + // C[i] = R[i] + return append(A[:8], R...), nil +} + +// PadBuffer pads byte buffer buf to a length being multiple of +// blockLen. Additional bytes appended to the buffer have value of the +// number padded bytes. E.g. if the buffer is 3 bytes short of being +// 40 bytes total, the appended bytes will be [03, 03, 03]. +func PadBuffer(buf []byte, blockLen int) []byte { + padding := blockLen - (len(buf) % blockLen) + if padding == 0 { + return buf + } + + padBuf := make([]byte, padding) + for i := 0; i < padding; i++ { + padBuf[i] = byte(padding) + } + + return append(buf, padBuf...) +} + +// UnpadBuffer verifies that buffer contains proper padding and +// returns buffer without the padding, or nil if the padding was +// invalid. +func UnpadBuffer(buf []byte, dataLen int) []byte { + padding := len(buf) - dataLen + outBuf := buf[:dataLen] + + for i := dataLen; i < len(buf); i++ { + if buf[i] != byte(padding) { + // Invalid padding - bail out + return nil + } + } + + return outBuf +} + +func (e *PublicKey) Encrypt(random io.Reader, kdfParams []byte, plain []byte, hash crypto.Hash, kdfKeySize int) (Vx *big.Int, Vy *big.Int, C []byte, err error) { + // Vx, Vy - encryption key + + // Note for Curve 25519 - curve25519 library already does key + // clamping in scalarMult, so we can use generic random scalar + // generation from elliptic. + priv, Vx, Vy, err := elliptic.GenerateKey(e.Curve, random) + if err != nil { + return nil, nil, nil, err + } + + // Sx, Sy - shared secret + Sx, _ := e.Curve.ScalarMult(e.X, e.Y, priv) + + // Encrypt the payload with KDF-ed S as the encryption key. Pass + // the ciphertext along with V to the recipient. Recipient can + // generate S using V and their priv key, and then KDF(S), on + // their own, to get encryption key and decrypt the ciphertext, + // revealing encryption key for symmetric encryption later. + + plain = PadBuffer(plain, 8) + key := e.KDF(Sx.Bytes(), kdfParams, hash) + + // Take only as many bytes from key as the key length (the hash + // result might be bigger) + encrypted, err := AESKeyWrap(key[:kdfKeySize], plain) + + return Vx, Vy, encrypted, nil +} + +func (e *PrivateKey) DecryptShared(X, Y *big.Int) []byte { + Sx, _ := e.Curve.ScalarMult(X, Y, e.X.Bytes()) + return Sx.Bytes() +} + +func countBits(buffer []byte) int { + var headerLen int + switch buffer[0] { + case 0x4: + headerLen = 3 + case 0x40: + headerLen = 7 + default: + // Unexpected header - but we can still count the bits. + val := buffer[0] + headerLen = 0 + for val > 0 { + val = val / 2 + headerLen++ + } + } + + return headerLen + (len(buffer)-1)*8 +} + +// elliptic.Marshal and elliptic.Unmarshal only marshals uncompressed +// 0x4 MPI types. These functions will check if the curve is cv25519, +// and if so, use 0x40 compressed type to (un)marshal. Otherwise, +// elliptic.(Un)marshal will be called. + +// Marshal encodes point into either 0x4 uncompressed point form, or +// 0x40 compressed point for Curve 25519. +func Marshal(curve elliptic.Curve, x, y *big.Int) (buf []byte, bitSize int) { + // NOTE: Read more about MPI encoding in the RFC: + // https://tools.ietf.org/html/rfc4880#section-3.2 + + // We are required to encode size in bits, counting from the most- + // significant non-zero bit. So assuming that the buffer never + // starts with 0x00, we only need to count bits in the first byte + // - and in current implentation it will always be 0x4 or 0x40. + + cv, ok := curve25519.ToCurve25519(curve) + if ok { + buf = cv.MarshalType40(x, y) + } else { + buf = elliptic.Marshal(curve, x, y) + } + + return buf, countBits(buf) +} + +// Unmarshal converts point, serialized by Marshal, into x, y pair. +// For 0x40 compressed points (for Curve 25519), y will always be 0. +// It is an error if point is not on the curve, On error, x = nil. +func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) { + cv, ok := curve25519.ToCurve25519(curve) + if ok { + return cv.UnmarshalType40(data) + } + + return elliptic.Unmarshal(curve, data) +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/elgamal/elgamal.go b/vendor/github.com/keybase/go-crypto/openpgp/elgamal/elgamal.go new file mode 100644 index 000000000..15dafc556 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/elgamal/elgamal.go @@ -0,0 +1,122 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package elgamal implements ElGamal encryption, suitable for OpenPGP, +// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on +// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31, +// n. 4, 1985, pp. 469-472. +// +// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it +// unsuitable for other protocols. RSA should be used in preference in any +// case. +package elgamal // import "github.com/keybase/go-crypto/openpgp/elgamal" + +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "io" + "math/big" +) + +// PublicKey represents an ElGamal public key. +type PublicKey struct { + G, P, Y *big.Int +} + +// PrivateKey represents an ElGamal private key. +type PrivateKey struct { + PublicKey + X *big.Int +} + +// Encrypt encrypts the given message to the given public key. The result is a +// pair of integers. Errors can result from reading random, or because msg is +// too large to be encrypted to the public key. +func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) { + pLen := (pub.P.BitLen() + 7) / 8 + if len(msg) > pLen-11 { + err = errors.New("elgamal: message too long") + return + } + + // EM = 0x02 || PS || 0x00 || M + em := make([]byte, pLen-1) + em[0] = 2 + ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] + err = nonZeroRandomBytes(ps, random) + if err != nil { + return + } + em[len(em)-len(msg)-1] = 0 + copy(mm, msg) + + m := new(big.Int).SetBytes(em) + + k, err := rand.Int(random, pub.P) + if err != nil { + return + } + + c1 = new(big.Int).Exp(pub.G, k, pub.P) + s := new(big.Int).Exp(pub.Y, k, pub.P) + c2 = s.Mul(s, m) + c2.Mod(c2, pub.P) + + return +} + +// Decrypt takes two integers, resulting from an ElGamal encryption, and +// returns the plaintext of the message. An error can result only if the +// ciphertext is invalid. Users should keep in mind that this is a padding +// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can +// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks +// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel +// Bleichenbacher, Advances in Cryptology (Crypto '98), +func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { + s := new(big.Int).Exp(c1, priv.X, priv.P) + s.ModInverse(s, priv.P) + s.Mul(s, c2) + s.Mod(s, priv.P) + em := s.Bytes() + + firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) + + // The remainder of the plaintext must be a string of non-zero random + // octets, followed by a 0, followed by the message. + // lookingForIndex: 1 iff we are still looking for the zero. + // index: the offset of the first zero byte. + var lookingForIndex, index int + lookingForIndex = 1 + + for i := 1; i < len(em); i++ { + equals0 := subtle.ConstantTimeByteEq(em[i], 0) + index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) + lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) + } + + if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { + return nil, errors.New("elgamal: decryption error") + } + return em[index+1:], nil +} + +// nonZeroRandomBytes fills the given slice with non-zero random octets. +func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { + _, err = io.ReadFull(rand, s) + if err != nil { + return + } + + for i := 0; i < len(s); i++ { + for s[i] == 0 { + _, err = io.ReadFull(rand, s[i:i+1]) + if err != nil { + return + } + } + } + + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/errors/errors.go b/vendor/github.com/keybase/go-crypto/openpgp/errors/errors.go new file mode 100644 index 000000000..855fa89c1 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/errors/errors.go @@ -0,0 +1,80 @@ +// Copyright 2010 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 errors contains common error types for the OpenPGP packages. +package errors // import "github.com/keybase/go-crypto/openpgp/errors" + +import ( + "strconv" +) + +// A StructuralError is returned when OpenPGP data is found to be syntactically +// invalid. +type StructuralError string + +func (s StructuralError) Error() string { + return "openpgp: invalid data: " + string(s) +} + +// UnsupportedError indicates that, although the OpenPGP data is valid, it +// makes use of currently unimplemented features. +type UnsupportedError string + +func (s UnsupportedError) Error() string { + return "openpgp: unsupported feature: " + string(s) +} + +// InvalidArgumentError indicates that the caller is in error and passed an +// incorrect value. +type InvalidArgumentError string + +func (i InvalidArgumentError) Error() string { + return "openpgp: invalid argument: " + string(i) +} + +// SignatureError indicates that a syntactically valid signature failed to +// validate. +type SignatureError string + +func (b SignatureError) Error() string { + return "openpgp: invalid signature: " + string(b) +} + +type keyIncorrectError int + +func (ki keyIncorrectError) Error() string { + return "openpgp: incorrect key" +} + +var ErrKeyIncorrect error = keyIncorrectError(0) + +type unknownIssuerError int + +func (unknownIssuerError) Error() string { + return "openpgp: signature made by unknown entity" +} + +var ErrUnknownIssuer error = unknownIssuerError(0) + +type keyRevokedError int + +func (keyRevokedError) Error() string { + return "openpgp: signature made by revoked key" +} + +var ErrKeyRevoked error = keyRevokedError(0) + +type UnknownPacketTypeError uint8 + +func (upte UnknownPacketTypeError) Error() string { + return "openpgp: unknown packet type: " + strconv.Itoa(int(upte)) +} + +// DeprecatedKeyError indicates that the key was read and verified +// properly, but uses a deprecated algorithm and can't be used. +type DeprecatedKeyError string + +func (d DeprecatedKeyError) Error() string { + return "openpgp: key is deprecated: " + string(d) +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/keys.go b/vendor/github.com/keybase/go-crypto/openpgp/keys.go new file mode 100644 index 000000000..62ee323a7 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/keys.go @@ -0,0 +1,911 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package openpgp + +import ( + "crypto/hmac" + "encoding/binary" + "io" + "time" + + "github.com/keybase/go-crypto/openpgp/armor" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/packet" + "github.com/keybase/go-crypto/rsa" +) + +// PublicKeyType is the armor type for a PGP public key. +var PublicKeyType = "PGP PUBLIC KEY BLOCK" + +// PrivateKeyType is the armor type for a PGP private key. +var PrivateKeyType = "PGP PRIVATE KEY BLOCK" + +// An Entity represents the components of an OpenPGP key: a primary public key +// (which must be a signing key), one or more identities claimed by that key, +// and zero or more subkeys, which may be encryption keys. +type Entity struct { + PrimaryKey *packet.PublicKey + PrivateKey *packet.PrivateKey + Identities map[string]*Identity // indexed by Identity.Name + Revocations []*packet.Signature + // Revocations that are signed by designated revokers. Reading keys + // will not verify these revocations, because it won't have access to + // issuers' public keys, API consumers should do this instead (or + // not, and just assume that the key is probably revoked). + UnverifiedRevocations []*packet.Signature + Subkeys []Subkey + BadSubkeys []BadSubkey +} + +// An Identity represents an identity claimed by an Entity and zero or more +// assertions by other entities about that claim. +type Identity struct { + Name string // by convention, has the form "Full Name (comment) " + UserId *packet.UserId + SelfSignature *packet.Signature + Signatures []*packet.Signature + Revocation *packet.Signature +} + +// A Subkey is an additional public key in an Entity. Subkeys can be used for +// encryption. +type Subkey struct { + PublicKey *packet.PublicKey + PrivateKey *packet.PrivateKey + Sig *packet.Signature + Revocation *packet.Signature +} + +// BadSubkey is one that failed reconstruction, but we'll keep it around for +// informational purposes. +type BadSubkey struct { + Subkey + Err error +} + +// A Key identifies a specific public key in an Entity. This is either the +// Entity's primary key or a subkey. +type Key struct { + Entity *Entity + PublicKey *packet.PublicKey + PrivateKey *packet.PrivateKey + SelfSignature *packet.Signature + KeyFlags packet.KeyFlagBits +} + +// A KeyRing provides access to public and private keys. +type KeyRing interface { + + // KeysById returns the set of keys that have the given key id. + // fp can be optionally supplied, which is the full key fingerprint. + // If it's provided, then it must match. This comes up in the case + // of GPG subpacket 33. + KeysById(id uint64, fp []byte) []Key + + // KeysByIdAndUsage returns the set of keys with the given id + // that also meet the key usage given by requiredUsage. + // The requiredUsage is expressed as the bitwise-OR of + // packet.KeyFlag* values. + // fp can be optionally supplied, which is the full key fingerprint. + // If it's provided, then it must match. This comes up in the case + // of GPG subpacket 33. + KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) []Key + + // DecryptionKeys returns all private keys that are valid for + // decryption. + DecryptionKeys() []Key +} + +// primaryIdentity returns the Identity marked as primary or the first identity +// if none are so marked. +func (e *Entity) primaryIdentity() *Identity { + var firstIdentity *Identity + for _, ident := range e.Identities { + if firstIdentity == nil { + firstIdentity = ident + } + if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + return ident + } + } + return firstIdentity +} + +// encryptionKey returns the best candidate Key for encrypting a message to the +// given Entity. +func (e *Entity) encryptionKey(now time.Time) (Key, bool) { + candidateSubkey := -1 + + // Iterate the keys to find the newest key + var maxTime time.Time + for i, subkey := range e.Subkeys { + + // NOTE(maxtaco) + // If there is a Flags subpacket, then we have to follow it, and only + // use keys that are marked for Encryption of Communication. If there + // isn't a Flags subpacket, and this is an Encrypt-Only key (right now only ElGamal + // suffices), then we implicitly use it. The check for primary below is a little + // more open-ended, but for now, let's be strict and potentially open up + // if we see bugs in the wild. + // + // One more note: old DSA/ElGamal keys tend not to have the Flags subpacket, + // so this sort of thing is pretty important for encrypting to older keys. + // + if ((subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications) || + (!subkey.Sig.FlagsValid && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal)) && + subkey.PublicKey.PubKeyAlgo.CanEncrypt() && + !subkey.Sig.KeyExpired(now) && + subkey.Revocation == nil && + (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { + candidateSubkey = i + maxTime = subkey.Sig.CreationTime + } + } + + if candidateSubkey != -1 { + subkey := e.Subkeys[candidateSubkey] + return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true + } + + // If we don't have any candidate subkeys for encryption and + // the primary key doesn't have any usage metadata then we + // assume that the primary key is ok. Or, if the primary key is + // marked as ok to encrypt to, then we can obviously use it. + // + // NOTE(maxtaco) - see note above, how this policy is a little too open-ended + // for my liking, but leave it for now. + i := e.primaryIdentity() + if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications) && + e.PrimaryKey.PubKeyAlgo.CanEncrypt() && + !i.SelfSignature.KeyExpired(now) { + return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true + } + + // This Entity appears to be signing only. + return Key{}, false +} + +// signingKey return the best candidate Key for signing a message with this +// Entity. +func (e *Entity) signingKey(now time.Time) (Key, bool) { + candidateSubkey := -1 + + for i, subkey := range e.Subkeys { + if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) && + subkey.PrivateKey.PrivateKey != nil && + subkey.PublicKey.PubKeyAlgo.CanSign() && + subkey.Revocation == nil && + !subkey.Sig.KeyExpired(now) { + candidateSubkey = i + break + } + } + + if candidateSubkey != -1 { + subkey := e.Subkeys[candidateSubkey] + return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true + } + + // If we have no candidate subkey then we assume that it's ok to sign + // with the primary key. + i := e.primaryIdentity() + if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign) && + e.PrimaryKey.PubKeyAlgo.CanSign() && + !i.SelfSignature.KeyExpired(now) && + e.PrivateKey.PrivateKey != nil { + return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true + } + + return Key{}, false +} + +// An EntityList contains one or more Entities. +type EntityList []*Entity + +func keyMatchesIdAndFingerprint(key *packet.PublicKey, id uint64, fp []byte) bool { + if key.KeyId != id { + return false + } + if fp == nil { + return true + } + return hmac.Equal(fp, key.Fingerprint[:]) +} + +// KeysById returns the set of keys that have the given key id. +// fp can be optionally supplied, which is the full key fingerprint. +// If it's provided, then it must match. This comes up in the case +// of GPG subpacket 33. +func (el EntityList) KeysById(id uint64, fp []byte) (keys []Key) { + for _, e := range el { + if keyMatchesIdAndFingerprint(e.PrimaryKey, id, fp) { + var selfSig *packet.Signature + for _, ident := range e.Identities { + if selfSig == nil { + selfSig = ident.SelfSignature + } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + selfSig = ident.SelfSignature + break + } + } + + var keyFlags packet.KeyFlagBits + for _, ident := range e.Identities { + keyFlags.Merge(ident.SelfSignature.GetKeyFlags()) + } + + keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, keyFlags}) + } + + for _, subKey := range e.Subkeys { + if keyMatchesIdAndFingerprint(subKey.PublicKey, id, fp) { + + // If there's both a a revocation and a sig, then take the + // revocation. Otherwise, we can proceed with the sig. + sig := subKey.Revocation + if sig == nil { + sig = subKey.Sig + } + + keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, sig, sig.GetKeyFlags()}) + } + } + } + return +} + +// KeysByIdAndUsage returns the set of keys with the given id that also meet +// the key usage given by requiredUsage. The requiredUsage is expressed as +// the bitwise-OR of packet.KeyFlag* values. +// fp can be optionally supplied, which is the full key fingerprint. +// If it's provided, then it must match. This comes up in the case +// of GPG subpacket 33. +func (el EntityList) KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) (keys []Key) { + for _, key := range el.KeysById(id, fp) { + if len(key.Entity.Revocations) > 0 { + continue + } + + if key.SelfSignature.RevocationReason != nil { + continue + } + + if requiredUsage != 0 { + var usage byte + + switch { + case key.KeyFlags.Valid: + usage = key.KeyFlags.BitField + + case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal: + // We also need to handle the case where, although the sig's + // flags aren't valid, the key can is implicitly usable for + // encryption by virtue of being ElGamal. See also the comment + // in encryptionKey() above. + usage |= packet.KeyFlagEncryptCommunications + usage |= packet.KeyFlagEncryptStorage + + case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoDSA || + key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoECDSA || + key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA: + usage |= packet.KeyFlagSign + + // For a primary RSA key without any key flags, be as permissiable + // as possible. + case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoRSA && + keyMatchesIdAndFingerprint(key.Entity.PrimaryKey, id, fp): + usage = (packet.KeyFlagCertify | packet.KeyFlagSign | + packet.KeyFlagEncryptCommunications | packet.KeyFlagEncryptStorage) + } + + if usage&requiredUsage != requiredUsage { + continue + } + } + + keys = append(keys, key) + } + return +} + +// DecryptionKeys returns all private keys that are valid for decryption. +func (el EntityList) DecryptionKeys() (keys []Key) { + for _, e := range el { + for _, subKey := range e.Subkeys { + if subKey.PrivateKey != nil && subKey.PrivateKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) { + keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Sig.GetKeyFlags()}) + } + } + } + return +} + +// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file. +func ReadArmoredKeyRing(r io.Reader) (EntityList, error) { + block, err := armor.Decode(r) + if err == io.EOF { + return nil, errors.InvalidArgumentError("no armored data found") + } + if err != nil { + return nil, err + } + if block.Type != PublicKeyType && block.Type != PrivateKeyType { + return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type) + } + + return ReadKeyRing(block.Body) +} + +// ReadKeyRing reads one or more public/private keys. Unsupported keys are +// ignored as long as at least a single valid key is found. +func ReadKeyRing(r io.Reader) (el EntityList, err error) { + packets := packet.NewReader(r) + var lastUnsupportedError error + + for { + var e *Entity + e, err = ReadEntity(packets) + if err != nil { + // TODO: warn about skipped unsupported/unreadable keys + if _, ok := err.(errors.UnsupportedError); ok { + lastUnsupportedError = err + err = readToNextPublicKey(packets) + } else if _, ok := err.(errors.StructuralError); ok { + // Skip unreadable, badly-formatted keys + lastUnsupportedError = err + err = readToNextPublicKey(packets) + } + if err == io.EOF { + err = nil + break + } + if err != nil { + el = nil + break + } + } else { + el = append(el, e) + } + } + + if len(el) == 0 && err == nil { + err = lastUnsupportedError + } + return +} + +// readToNextPublicKey reads packets until the start of the entity and leaves +// the first packet of the new entity in the Reader. +func readToNextPublicKey(packets *packet.Reader) (err error) { + var p packet.Packet + for { + p, err = packets.Next() + if err == io.EOF { + return + } else if err != nil { + if _, ok := err.(errors.UnsupportedError); ok { + err = nil + continue + } + return + } + + if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey { + packets.Unread(p) + return + } + } + + panic("unreachable") +} + +// ReadEntity reads an entity (public key, identities, subkeys etc) from the +// given Reader. +func ReadEntity(packets *packet.Reader) (*Entity, error) { + e := new(Entity) + e.Identities = make(map[string]*Identity) + + p, err := packets.Next() + if err != nil { + return nil, err + } + + var ok bool + if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok { + if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok { + packets.Unread(p) + return nil, errors.StructuralError("first packet was not a public/private key") + } else { + e.PrimaryKey = &e.PrivateKey.PublicKey + } + } + + if !e.PrimaryKey.PubKeyAlgo.CanSign() { + return nil, errors.StructuralError("primary key cannot be used for signatures") + } + + var current *Identity + var revocations []*packet.Signature + + designatedRevokers := make(map[uint64]bool) +EachPacket: + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return nil, err + } + switch pkt := p.(type) { + case *packet.UserId: + + // Make a new Identity object, that we might wind up throwing away. + // We'll only add it if we get a valid self-signature over this + // userID. + current = new(Identity) + current.Name = pkt.Id + current.UserId = pkt + case *packet.Signature: + if pkt.SigType == packet.SigTypeKeyRevocation { + // These revocations won't revoke UIDs (see + // SigTypeIdentityRevocation). Handle these first, + // because key might have revocation coming from + // another key (designated revoke). + revocations = append(revocations, pkt) + continue + } + + // These are signatures by other people on this key. Let's just ignore them + // from the beginning, since they shouldn't affect our key decoding one way + // or the other. + if pkt.IssuerKeyId != nil && *pkt.IssuerKeyId != e.PrimaryKey.KeyId { + continue + } + + // If this is a signature made by the keyholder, and the signature has stubbed out + // critical packets, then *now* we need to bail out. + if e := pkt.StubbedOutCriticalError; e != nil { + return nil, e + } + + // Next handle the case of a self-signature. According to RFC8440, + // Section 5.2.3.3, if there are several self-signatures, + // we should take the newer one. If they were both created + // at the same time, but one of them has keyflags specified and the + // other doesn't, keep the one with the keyflags. We have actually + // seen this in the wild (see the 'Yield' test in read_test.go). + // If there is a tie, and both have the same value for FlagsValid, + // then "last writer wins." + // + // HOWEVER! We have seen yet more keys in the wild (see the 'Spiros' + // test in read_test.go), in which the later self-signature is a bunch + // of junk, and doesn't even specify key flags. Does it really make + // sense to overwrite reasonable key flags with the empty set? I'm not + // sure what that would be trying to achieve, and plus GPG seems to be + // ok with this situation, and ignores the later (empty) keyflag set. + // So further tighten our overwrite rules, and only allow the later + // signature to overwrite the earlier signature if so doing won't + // trash the key flags. + if current != nil && + (current.SelfSignature == nil || + (!pkt.CreationTime.Before(current.SelfSignature.CreationTime) && + (pkt.FlagsValid || !current.SelfSignature.FlagsValid))) && + (pkt.SigType == packet.SigTypePositiveCert || pkt.SigType == packet.SigTypeGenericCert) && + pkt.IssuerKeyId != nil && + *pkt.IssuerKeyId == e.PrimaryKey.KeyId { + + if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil { + + current.SelfSignature = pkt + + // NOTE(maxtaco) 2016.01.11 + // Only register an identity once we've gotten a valid self-signature. + // It's possible therefore for us to throw away `current` in the case + // no valid self-signatures were found. That's OK as long as there are + // other identies that make sense. + // + // NOTE! We might later see a revocation for this very same UID, and it + // won't be undone. We've preserved this feature from the original + // Google OpenPGP we forked from. + e.Identities[current.Name] = current + } else { + // We really should warn that there was a failure here. Not raise an error + // since this really shouldn't be a fail-stop error. + } + } else if current != nil && pkt.SigType == packet.SigTypeIdentityRevocation { + if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil { + // Note: we are not removing the identity from + // e.Identities. Caller can always filter by Revocation + // field to ignore revoked identities. + current.Revocation = pkt + } + } else if pkt.SigType == packet.SigTypeDirectSignature { + if err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, pkt); err == nil { + if desig := pkt.DesignatedRevoker; desig != nil { + // If it's a designated revoker signature, take last 8 octects + // of fingerprint as Key ID and save it to designatedRevokers + // map. We consult this map later to see if a foreign + // revocation should be added to UnverifiedRevocations. + keyID := binary.BigEndian.Uint64(desig.Fingerprint[len(desig.Fingerprint)-8:]) + designatedRevokers[keyID] = true + } + } + } else if current == nil { + // NOTE(maxtaco) + // + // See https://github.com/keybase/client/issues/2666 + // + // There might have been a user attribute picture before this signature, + // in which case this is still a valid PGP key. In the future we might + // not ignore user attributes (like picture). But either way, it doesn't + // make sense to bail out here. Keep looking for other valid signatures. + // + // Used to be: + // return nil, errors.StructuralError("signature packet found before user id packet") + } else { + current.Signatures = append(current.Signatures, pkt) + } + case *packet.PrivateKey: + if pkt.IsSubkey == false { + packets.Unread(p) + break EachPacket + } + err = addSubkey(e, packets, &pkt.PublicKey, pkt) + if err != nil { + return nil, err + } + case *packet.PublicKey: + if pkt.IsSubkey == false { + packets.Unread(p) + break EachPacket + } + err = addSubkey(e, packets, pkt, nil) + if err != nil { + return nil, err + } + default: + // we ignore unknown packets + } + } + + if len(e.Identities) == 0 { + return nil, errors.StructuralError("entity without any identities") + } + + for _, revocation := range revocations { + if revocation.IssuerKeyId == nil || *revocation.IssuerKeyId == e.PrimaryKey.KeyId { + // Key revokes itself, something that we can verify. + err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, revocation) + if err == nil { + e.Revocations = append(e.Revocations, revocation) + } else { + return nil, errors.StructuralError("revocation signature signed by alternate key") + } + } else if revocation.IssuerKeyId != nil { + if _, ok := designatedRevokers[*revocation.IssuerKeyId]; ok { + // Revocation is done by certified designated revoker, + // but we can't verify the revocation. + e.UnverifiedRevocations = append(e.UnverifiedRevocations, revocation) + } + } + } + + return e, nil +} + +func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { + var subKey Subkey + subKey.PublicKey = pub + subKey.PrivateKey = priv + var lastErr error + for { + p, err := packets.Next() + if err == io.EOF { + break + } + if err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + sig, ok := p.(*packet.Signature) + if !ok { + // Hit a non-signature packet, so assume we're up to the next key + packets.Unread(p) + break + } + if st := sig.SigType; st != packet.SigTypeSubkeyBinding && st != packet.SigTypeSubkeyRevocation { + + // Note(maxtaco): + // We used to error out here, but instead, let's fast-forward past + // packets that are in the wrong place (like misplaced 0x13 signatures) + // until we get to one that works. For a test case, + // see TestWithBadSubkeySignaturePackets. + + continue + } + err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig) + if err != nil { + // Non valid signature, so again, no need to abandon all hope, just continue; + // make a note of the error we hit. + lastErr = errors.StructuralError("subkey signature invalid: " + err.Error()) + continue + } + switch sig.SigType { + case packet.SigTypeSubkeyBinding: + // Does the "new" sig set expiration to later date than + // "previous" sig? + if subKey.Sig == nil || subKey.Sig.ExpiresBeforeOther(sig) { + subKey.Sig = sig + } + case packet.SigTypeSubkeyRevocation: + // First writer wins + if subKey.Revocation == nil { + subKey.Revocation = sig + } + } + } + + if subKey.Sig != nil { + if err := subKey.PublicKey.ErrorIfDeprecated(); err != nil { + // Key passed signature check but is deprecated. + subKey.Sig = nil + lastErr = err + } + } + + if subKey.Sig != nil { + e.Subkeys = append(e.Subkeys, subKey) + } else { + if lastErr == nil { + lastErr = errors.StructuralError("Subkey wasn't signed; expected a 'binding' signature") + } + e.BadSubkeys = append(e.BadSubkeys, BadSubkey{Subkey: subKey, Err: lastErr}) + } + return nil +} + +const defaultRSAKeyBits = 2048 + +// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a +// single identity composed of the given full name, comment and email, any of +// which may be empty but must not contain any of "()<>\x00". +// If config is nil, sensible defaults will be used. +func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) { + currentTime := config.Now() + + bits := defaultRSAKeyBits + if config != nil && config.RSABits != 0 { + bits = config.RSABits + } + + uid := packet.NewUserId(name, comment, email) + if uid == nil { + return nil, errors.InvalidArgumentError("user id field contained invalid characters") + } + signingPriv, err := rsa.GenerateKey(config.Random(), bits) + if err != nil { + return nil, err + } + encryptingPriv, err := rsa.GenerateKey(config.Random(), bits) + if err != nil { + return nil, err + } + + e := &Entity{ + PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey), + PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv), + Identities: make(map[string]*Identity), + } + isPrimaryId := true + e.Identities[uid.Id] = &Identity{ + Name: uid.Name, + UserId: uid, + SelfSignature: &packet.Signature{ + CreationTime: currentTime, + SigType: packet.SigTypePositiveCert, + PubKeyAlgo: packet.PubKeyAlgoRSA, + Hash: config.Hash(), + IsPrimaryId: &isPrimaryId, + FlagsValid: true, + FlagSign: true, + FlagCertify: true, + IssuerKeyId: &e.PrimaryKey.KeyId, + }, + } + + e.Subkeys = make([]Subkey, 1) + e.Subkeys[0] = Subkey{ + PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey), + PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv), + Sig: &packet.Signature{ + CreationTime: currentTime, + SigType: packet.SigTypeSubkeyBinding, + PubKeyAlgo: packet.PubKeyAlgoRSA, + Hash: config.Hash(), + FlagsValid: true, + FlagEncryptStorage: true, + FlagEncryptCommunications: true, + IssuerKeyId: &e.PrimaryKey.KeyId, + }, + } + e.Subkeys[0].PublicKey.IsSubkey = true + e.Subkeys[0].PrivateKey.IsSubkey = true + + return e, nil +} + +// SerializePrivate serializes an Entity, including private key material, to +// the given Writer. For now, it must only be used on an Entity returned from +// NewEntity. +// If config is nil, sensible defaults will be used. +func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { + err = e.PrivateKey.Serialize(w) + if err != nil { + return + } + for _, ident := range e.Identities { + err = ident.UserId.Serialize(w) + if err != nil { + return + } + if e.PrivateKey.PrivateKey != nil { + err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config) + if err != nil { + return + } + } + err = ident.SelfSignature.Serialize(w) + if err != nil { + return + } + } + for _, subkey := range e.Subkeys { + err = subkey.PrivateKey.Serialize(w) + if err != nil { + return + } + // Workaround shortcoming of SignKey(), which doesn't work to reverse-sign + // sub-signing keys. So if requested, just reuse the signatures already + // available to us (if we read this key from a keyring). + if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() { + err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config) + if err != nil { + return + } + } + + if subkey.Revocation != nil { + err = subkey.Revocation.Serialize(w) + if err != nil { + return + } + } + + err = subkey.Sig.Serialize(w) + if err != nil { + return + } + } + return nil +} + +// Serialize writes the public part of the given Entity to w. (No private +// key material will be output). +func (e *Entity) Serialize(w io.Writer) error { + err := e.PrimaryKey.Serialize(w) + if err != nil { + return err + } + for _, ident := range e.Identities { + err = ident.UserId.Serialize(w) + if err != nil { + return err + } + err = ident.SelfSignature.Serialize(w) + if err != nil { + return err + } + for _, sig := range ident.Signatures { + err = sig.Serialize(w) + if err != nil { + return err + } + } + } + for _, subkey := range e.Subkeys { + err = subkey.PublicKey.Serialize(w) + if err != nil { + return err + } + + if subkey.Revocation != nil { + err = subkey.Revocation.Serialize(w) + if err != nil { + return err + } + } + err = subkey.Sig.Serialize(w) + if err != nil { + return err + } + } + return nil +} + +// SignIdentity adds a signature to e, from signer, attesting that identity is +// associated with e. The provided identity must already be an element of +// e.Identities and the private key of signer must have been decrypted if +// necessary. +// If config is nil, sensible defaults will be used. +func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error { + if signer.PrivateKey == nil { + return errors.InvalidArgumentError("signing Entity must have a private key") + } + if signer.PrivateKey.Encrypted { + return errors.InvalidArgumentError("signing Entity's private key must be decrypted") + } + ident, ok := e.Identities[identity] + if !ok { + return errors.InvalidArgumentError("given identity string not found in Entity") + } + + sig := &packet.Signature{ + SigType: packet.SigTypeGenericCert, + PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, + Hash: config.Hash(), + CreationTime: config.Now(), + IssuerKeyId: &signer.PrivateKey.KeyId, + } + if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil { + return err + } + ident.Signatures = append(ident.Signatures, sig) + return nil +} + +// CopySubkeyRevocations copies subkey revocations from the src Entity over +// to the receiver entity. We need this because `gpg --export-secret-key` does +// not appear to output subkey revocations. In this case we need to manually +// merge with the output of `gpg --export`. +func (e *Entity) CopySubkeyRevocations(src *Entity) { + m := make(map[[20]byte]*packet.Signature) + for _, subkey := range src.Subkeys { + if subkey.Revocation != nil { + m[subkey.PublicKey.Fingerprint] = subkey.Revocation + } + } + for i, subkey := range e.Subkeys { + if r := m[subkey.PublicKey.Fingerprint]; r != nil { + e.Subkeys[i].Revocation = r + } + } +} + +// CheckDesignatedRevokers will try to confirm any of designated +// revocation of entity. For this function to work, revocation +// issuer's key should be found in keyring. First successfully +// verified designated revocation is returned along with the key that +// verified it. +func FindVerifiedDesignatedRevoke(keyring KeyRing, entity *Entity) (*packet.Signature, *Key) { + for _, sig := range entity.UnverifiedRevocations { + if sig.IssuerKeyId == nil { + continue + } + + issuerKeyId := *sig.IssuerKeyId + issuerFingerprint := sig.IssuerFingerprint + keys := keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign) + if len(keys) == 0 { + continue + } + for _, key := range keys { + err := key.PublicKey.VerifyRevocationSignature(entity.PrimaryKey, sig) + if err == nil { + return sig, &key + } + } + } + + return nil, nil +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/compressed.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/compressed.go new file mode 100644 index 000000000..f023fe533 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/compressed.go @@ -0,0 +1,124 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "compress/bzip2" + "compress/flate" + "compress/zlib" + "io" + "strconv" + + "github.com/keybase/go-crypto/openpgp/errors" +) + +// Compressed represents a compressed OpenPGP packet. The decompressed contents +// will contain more OpenPGP packets. See RFC 4880, section 5.6. +type Compressed struct { + Body io.Reader +} + +const ( + NoCompression = flate.NoCompression + BestSpeed = flate.BestSpeed + BestCompression = flate.BestCompression + DefaultCompression = flate.DefaultCompression +) + +// CompressionConfig contains compressor configuration settings. +type CompressionConfig struct { + // Level is the compression level to use. It must be set to + // between -1 and 9, with -1 causing the compressor to use the + // default compression level, 0 causing the compressor to use + // no compression and 1 to 9 representing increasing (better, + // slower) compression levels. If Level is less than -1 or + // more then 9, a non-nil error will be returned during + // encryption. See the constants above for convenient common + // settings for Level. + Level int +} + +func (c *Compressed) parse(r io.Reader) error { + var buf [1]byte + _, err := readFull(r, buf[:]) + if err != nil { + return err + } + + switch buf[0] { + case 1: + c.Body = flate.NewReader(r) + case 2: + c.Body, err = zlib.NewReader(r) + case 3: + c.Body = bzip2.NewReader(r) + default: + err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0]))) + } + + return err +} + +// compressedWriterCloser represents the serialized compression stream +// header and the compressor. Its Close() method ensures that both the +// compressor and serialized stream header are closed. Its Write() +// method writes to the compressor. +type compressedWriteCloser struct { + sh io.Closer // Stream Header + c io.WriteCloser // Compressor +} + +func (cwc compressedWriteCloser) Write(p []byte) (int, error) { + return cwc.c.Write(p) +} + +func (cwc compressedWriteCloser) Close() (err error) { + err = cwc.c.Close() + if err != nil { + return err + } + + return cwc.sh.Close() +} + +// SerializeCompressed serializes a compressed data packet to w and +// returns a WriteCloser to which the literal data packets themselves +// can be written and which MUST be closed on completion. If cc is +// nil, sensible defaults will be used to configure the compression +// algorithm. +func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) { + compressed, err := serializeStreamHeader(w, packetTypeCompressed) + if err != nil { + return + } + + _, err = compressed.Write([]byte{uint8(algo)}) + if err != nil { + return + } + + level := DefaultCompression + if cc != nil { + level = cc.Level + } + + var compressor io.WriteCloser + switch algo { + case CompressionZIP: + compressor, err = flate.NewWriter(compressed, level) + case CompressionZLIB: + compressor, err = zlib.NewWriterLevel(compressed, level) + default: + s := strconv.Itoa(int(algo)) + err = errors.UnsupportedError("Unsupported compression algorithm: " + s) + } + if err != nil { + return + } + + literaldata = compressedWriteCloser{compressed, compressor} + + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/config.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/config.go new file mode 100644 index 000000000..f4125e189 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/config.go @@ -0,0 +1,98 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "crypto" + "crypto/rand" + "io" + "time" +) + +// Config collects a number of parameters along with sensible defaults. +// A nil *Config is valid and results in all default values. +type Config struct { + // Rand provides the source of entropy. + // If nil, the crypto/rand Reader is used. + Rand io.Reader + // DefaultHash is the default hash function to be used. + // If zero, SHA-256 is used. + DefaultHash crypto.Hash + // DefaultCipher is the cipher to be used. + // If zero, AES-128 is used. + DefaultCipher CipherFunction + // Time returns the current time as the number of seconds since the + // epoch. If Time is nil, time.Now is used. + Time func() time.Time + // DefaultCompressionAlgo is the compression algorithm to be + // applied to the plaintext before encryption. If zero, no + // compression is done. + DefaultCompressionAlgo CompressionAlgo + // CompressionConfig configures the compression settings. + CompressionConfig *CompressionConfig + // S2KCount is only used for symmetric encryption. It + // determines the strength of the passphrase stretching when + // the said passphrase is hashed to produce a key. S2KCount + // should be between 1024 and 65011712, inclusive. If Config + // is nil or S2KCount is 0, the value 65536 used. Not all + // values in the above range can be represented. S2KCount will + // be rounded up to the next representable value if it cannot + // be encoded exactly. When set, it is strongly encrouraged to + // use a value that is at least 65536. See RFC 4880 Section + // 3.7.1.3. + S2KCount int + // RSABits is the number of bits in new RSA keys made with NewEntity. + // If zero, then 2048 bit keys are created. + RSABits int + // ReuseSignatures tells us to reuse existing Signatures + // on serialized output. + ReuseSignaturesOnSerialize bool +} + +func (c *Config) Random() io.Reader { + if c == nil || c.Rand == nil { + return rand.Reader + } + return c.Rand +} + +func (c *Config) Hash() crypto.Hash { + if c == nil || uint(c.DefaultHash) == 0 { + return crypto.SHA256 + } + return c.DefaultHash +} + +func (c *Config) Cipher() CipherFunction { + if c == nil || uint8(c.DefaultCipher) == 0 { + return CipherAES128 + } + return c.DefaultCipher +} + +func (c *Config) Now() time.Time { + if c == nil || c.Time == nil { + return time.Now() + } + return c.Time() +} + +func (c *Config) Compression() CompressionAlgo { + if c == nil { + return CompressionNone + } + return c.DefaultCompressionAlgo +} + +func (c *Config) PasswordHashIterations() int { + if c == nil || c.S2KCount == 0 { + return 0 + } + return c.S2KCount +} + +func (c *Config) ReuseSignatures() bool { + return c != nil && c.ReuseSignaturesOnSerialize +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/ecdh.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/ecdh.go new file mode 100644 index 000000000..41de661d7 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/ecdh.go @@ -0,0 +1,104 @@ +package packet + +import ( + "bytes" + "io" + "math/big" + + "github.com/keybase/go-crypto/openpgp/ecdh" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/s2k" +) + +// ECDHKdfParams generates KDF parameters sequence for given +// PublicKey. See https://tools.ietf.org/html/rfc6637#section-8 +func ECDHKdfParams(pub *PublicKey) []byte { + buf := new(bytes.Buffer) + oid := pub.ec.oid + buf.WriteByte(byte(len(oid))) + buf.Write(oid) + buf.WriteByte(18) // ECDH TYPE + pub.ecdh.serialize(buf) + buf.WriteString("Anonymous Sender ") + buf.Write(pub.Fingerprint[:]) + return buf.Bytes() +} + +func decryptKeyECDH(priv *PrivateKey, X, Y *big.Int, C []byte) (out []byte, err error) { + ecdhpriv, ok := priv.PrivateKey.(*ecdh.PrivateKey) + if !ok { + return nil, errors.InvalidArgumentError("bad internal ECDH key") + } + + Sx := ecdhpriv.DecryptShared(X, Y) + + kdfParams := ECDHKdfParams(&priv.PublicKey) + hash, ok := s2k.HashIdToHash(byte(priv.ecdh.KdfHash)) + if !ok { + return nil, errors.InvalidArgumentError("invalid hash id in private key") + } + + key := ecdhpriv.KDF(Sx, kdfParams, hash) + keySize := CipherFunction(priv.ecdh.KdfAlgo).KeySize() + + decrypted, err := ecdh.AESKeyUnwrap(key[:keySize], C) + if err != nil { + return nil, err + } + + // We have to "read ahead" to discover real length of the + // encryption key and properly unpad buffer. + cipherFunc := CipherFunction(decrypted[0]) + // +3 bytes = 1-byte cipher id and checksum 2-byte checksum. + out = ecdh.UnpadBuffer(decrypted, cipherFunc.KeySize()+3) + if out == nil { + return nil, errors.InvalidArgumentError("invalid padding while ECDH") + } + return out, nil +} + +func serializeEncryptedKeyECDH(w io.Writer, rand io.Reader, header [10]byte, pub *PublicKey, keyBlock []byte) error { + ecdhpub := pub.PublicKey.(*ecdh.PublicKey) + kdfParams := ECDHKdfParams(pub) + + hash, ok := s2k.HashIdToHash(byte(pub.ecdh.KdfHash)) + if !ok { + return errors.InvalidArgumentError("invalid hash id in private key") + } + + kdfKeySize := CipherFunction(pub.ecdh.KdfAlgo).KeySize() + Vx, Vy, C, err := ecdhpub.Encrypt(rand, kdfParams, keyBlock, hash, kdfKeySize) + if err != nil { + return err + } + + mpis, mpiBitLen := ecdh.Marshal(ecdhpub.Curve, Vx, Vy) + + packetLen := len(header) /* header length in bytes */ + packetLen += 2 /* mpi length in bits */ + len(mpis) + packetLen += 1 /* ciphertext size in bytes */ + len(C) + + err = serializeHeader(w, packetTypeEncryptedKey, packetLen) + if err != nil { + return err + } + + _, err = w.Write(header[:]) + if err != nil { + return err + } + + _, err = w.Write([]byte{byte(mpiBitLen >> 8), byte(mpiBitLen)}) + if err != nil { + return err + } + + _, err = w.Write(mpis[:]) + if err != nil { + return err + } + + w.Write([]byte{byte(len(C))}) + w.Write(C[:]) + return nil +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/encrypted_key.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/encrypted_key.go new file mode 100644 index 000000000..58692ec8b --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/encrypted_key.go @@ -0,0 +1,226 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "encoding/binary" + "io" + "math/big" + "strconv" + + "github.com/keybase/go-crypto/openpgp/ecdh" + "github.com/keybase/go-crypto/openpgp/elgamal" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/rsa" +) + +const encryptedKeyVersion = 3 + +// EncryptedKey represents a public-key encrypted session key. See RFC 4880, +// section 5.1. +type EncryptedKey struct { + KeyId uint64 + Algo PublicKeyAlgorithm + CipherFunc CipherFunction // only valid after a successful Decrypt + Key []byte // only valid after a successful Decrypt + + encryptedMPI1, encryptedMPI2 parsedMPI + ecdh_C []byte +} + +func (e *EncryptedKey) parse(r io.Reader) (err error) { + var buf [10]byte + _, err = readFull(r, buf[:]) + if err != nil { + return + } + if buf[0] != encryptedKeyVersion { + return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0]))) + } + e.KeyId = binary.BigEndian.Uint64(buf[1:9]) + e.Algo = PublicKeyAlgorithm(buf[9]) + switch e.Algo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) + case PubKeyAlgoElGamal: + e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) + if err != nil { + return + } + e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) + case PubKeyAlgoECDH: + e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) + if err != nil { + return err + } + _, err = readFull(r, buf[:1]) // read C len (1 byte) + if err != nil { + return err + } + e.ecdh_C = make([]byte, int(buf[0])) + _, err = readFull(r, e.ecdh_C) + } + + if err != nil { + return err + } + + _, err = consumeAll(r) + return err +} + +func checksumKeyMaterial(key []byte) uint16 { + var checksum uint16 + for _, v := range key { + checksum += uint16(v) + } + return checksum +} + +// Decrypt decrypts an encrypted session key with the given private key. The +// private key must have been decrypted first. +// If config is nil, sensible defaults will be used. +func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { + var err error + var b []byte + + // TODO(agl): use session key decryption routines here to avoid + // padding oracle attacks. + switch priv.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) + case PubKeyAlgoElGamal: + c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) + c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) + b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) + case PubKeyAlgoECDH: + // Note: Unmarshal checks if point is on the curve. + c1, c2 := ecdh.Unmarshal(priv.PrivateKey.(*ecdh.PrivateKey).Curve, e.encryptedMPI1.bytes) + if c1 == nil { + return errors.InvalidArgumentError("failed to parse EC point for encryption key") + } + b, err = decryptKeyECDH(priv, c1, c2, e.ecdh_C) + default: + err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) + } + + if err != nil { + return err + } + + e.CipherFunc = CipherFunction(b[0]) + e.Key = b[1 : len(b)-2] + expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) + checksum := checksumKeyMaterial(e.Key) + if checksum != expectedChecksum { + return errors.StructuralError("EncryptedKey checksum incorrect") + } + + return nil +} + +// Serialize writes the encrypted key packet, e, to w. +func (e *EncryptedKey) Serialize(w io.Writer) error { + var mpiLen int + switch e.Algo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + mpiLen = 2 + len(e.encryptedMPI1.bytes) + case PubKeyAlgoElGamal: + mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes) + default: + return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo))) + } + + serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen) + + w.Write([]byte{encryptedKeyVersion}) + binary.Write(w, binary.BigEndian, e.KeyId) + w.Write([]byte{byte(e.Algo)}) + + switch e.Algo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + writeMPIs(w, e.encryptedMPI1) + case PubKeyAlgoElGamal: + writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2) + default: + panic("internal error") + } + + return nil +} + +// SerializeEncryptedKey serializes an encrypted key packet to w that contains +// key, encrypted to pub. +// If config is nil, sensible defaults will be used. +func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error { + var buf [10]byte + buf[0] = encryptedKeyVersion + binary.BigEndian.PutUint64(buf[1:9], pub.KeyId) + buf[9] = byte(pub.PubKeyAlgo) + + keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */) + keyBlock[0] = byte(cipherFunc) + copy(keyBlock[1:], key) + checksum := checksumKeyMaterial(key) + keyBlock[1+len(key)] = byte(checksum >> 8) + keyBlock[1+len(key)+1] = byte(checksum) + + switch pub.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) + case PubKeyAlgoElGamal: + return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) + case PubKeyAlgoECDH: + return serializeEncryptedKeyECDH(w, config.Random(), buf, pub, keyBlock) + case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: + return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) + } + + return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) +} + +func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error { + cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock) + if err != nil { + return errors.InvalidArgumentError("RSA encryption failed: " + err.Error()) + } + + packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText) + + err = serializeHeader(w, packetTypeEncryptedKey, packetLen) + if err != nil { + return err + } + _, err = w.Write(header[:]) + if err != nil { + return err + } + return writeMPI(w, 8*uint16(len(cipherText)), cipherText) +} + +func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error { + c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock) + if err != nil { + return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error()) + } + + packetLen := 10 /* header length */ + packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8 + packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8 + + err = serializeHeader(w, packetTypeEncryptedKey, packetLen) + if err != nil { + return err + } + _, err = w.Write(header[:]) + if err != nil { + return err + } + err = writeBig(w, c1) + if err != nil { + return err + } + return writeBig(w, c2) +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/literal.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/literal.go new file mode 100644 index 000000000..1a9ec6e51 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/literal.go @@ -0,0 +1,89 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "encoding/binary" + "io" +) + +// LiteralData represents an encrypted file. See RFC 4880, section 5.9. +type LiteralData struct { + IsBinary bool + FileName string + Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined. + Body io.Reader +} + +// ForEyesOnly returns whether the contents of the LiteralData have been marked +// as especially sensitive. +func (l *LiteralData) ForEyesOnly() bool { + return l.FileName == "_CONSOLE" +} + +func (l *LiteralData) parse(r io.Reader) (err error) { + var buf [256]byte + + _, err = readFull(r, buf[:2]) + if err != nil { + return + } + + l.IsBinary = buf[0] == 'b' + fileNameLen := int(buf[1]) + + _, err = readFull(r, buf[:fileNameLen]) + if err != nil { + return + } + + l.FileName = string(buf[:fileNameLen]) + + _, err = readFull(r, buf[:4]) + if err != nil { + return + } + + l.Time = binary.BigEndian.Uint32(buf[:4]) + l.Body = r + return +} + +// SerializeLiteral serializes a literal data packet to w and returns a +// WriteCloser to which the data itself can be written and which MUST be closed +// on completion. The fileName is truncated to 255 bytes. +func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) { + var buf [4]byte + buf[0] = 't' + if isBinary { + buf[0] = 'b' + } + if len(fileName) > 255 { + fileName = fileName[:255] + } + buf[1] = byte(len(fileName)) + + inner, err := serializeStreamHeader(w, packetTypeLiteralData) + if err != nil { + return + } + + _, err = inner.Write(buf[:2]) + if err != nil { + return + } + _, err = inner.Write([]byte(fileName)) + if err != nil { + return + } + binary.BigEndian.PutUint32(buf[:], time) + _, err = inner.Write(buf[:]) + if err != nil { + return + } + + plaintext = inner + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/ocfb.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/ocfb.go new file mode 100644 index 000000000..ce2a33a54 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/ocfb.go @@ -0,0 +1,143 @@ +// Copyright 2010 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. + +// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9 + +package packet + +import ( + "crypto/cipher" +) + +type ocfbEncrypter struct { + b cipher.Block + fre []byte + outUsed int +} + +// An OCFBResyncOption determines if the "resynchronization step" of OCFB is +// performed. +type OCFBResyncOption bool + +const ( + OCFBResync OCFBResyncOption = true + OCFBNoResync OCFBResyncOption = false +) + +// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's +// cipher feedback mode using the given cipher.Block, and an initial amount of +// ciphertext. randData must be random bytes and be the same length as the +// cipher.Block's block size. Resync determines if the "resynchronization step" +// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on +// this point. +func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) { + blockSize := block.BlockSize() + if len(randData) != blockSize { + return nil, nil + } + + x := &ocfbEncrypter{ + b: block, + fre: make([]byte, blockSize), + outUsed: 0, + } + prefix := make([]byte, blockSize+2) + + block.Encrypt(x.fre, x.fre) + for i := 0; i < blockSize; i++ { + prefix[i] = randData[i] ^ x.fre[i] + } + + block.Encrypt(x.fre, prefix[:blockSize]) + prefix[blockSize] = x.fre[0] ^ randData[blockSize-2] + prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1] + + if resync { + block.Encrypt(x.fre, prefix[2:]) + } else { + x.fre[0] = prefix[blockSize] + x.fre[1] = prefix[blockSize+1] + x.outUsed = 2 + } + return x, prefix +} + +func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) { + for i := 0; i < len(src); i++ { + if x.outUsed == len(x.fre) { + x.b.Encrypt(x.fre, x.fre) + x.outUsed = 0 + } + + x.fre[x.outUsed] ^= src[i] + dst[i] = x.fre[x.outUsed] + x.outUsed++ + } +} + +type ocfbDecrypter struct { + b cipher.Block + fre []byte + outUsed int +} + +// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's +// cipher feedback mode using the given cipher.Block. Prefix must be the first +// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's +// block size. If an incorrect key is detected then nil is returned. On +// successful exit, blockSize+2 bytes of decrypted data are written into +// prefix. Resync determines if the "resynchronization step" from RFC 4880, +// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point. +func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream { + blockSize := block.BlockSize() + if len(prefix) != blockSize+2 { + return nil + } + + x := &ocfbDecrypter{ + b: block, + fre: make([]byte, blockSize), + outUsed: 0, + } + prefixCopy := make([]byte, len(prefix)) + copy(prefixCopy, prefix) + + block.Encrypt(x.fre, x.fre) + for i := 0; i < blockSize; i++ { + prefixCopy[i] ^= x.fre[i] + } + + block.Encrypt(x.fre, prefix[:blockSize]) + prefixCopy[blockSize] ^= x.fre[0] + prefixCopy[blockSize+1] ^= x.fre[1] + + if prefixCopy[blockSize-2] != prefixCopy[blockSize] || + prefixCopy[blockSize-1] != prefixCopy[blockSize+1] { + return nil + } + + if resync { + block.Encrypt(x.fre, prefix[2:]) + } else { + x.fre[0] = prefix[blockSize] + x.fre[1] = prefix[blockSize+1] + x.outUsed = 2 + } + copy(prefix, prefixCopy) + return x +} + +func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) { + for i := 0; i < len(src); i++ { + if x.outUsed == len(x.fre) { + x.b.Encrypt(x.fre, x.fre) + x.outUsed = 0 + } + + c := src[i] + dst[i] = x.fre[x.outUsed] ^ src[i] + x.fre[x.outUsed] = c + x.outUsed++ + } +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/one_pass_signature.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/one_pass_signature.go new file mode 100644 index 000000000..af404bb10 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/one_pass_signature.go @@ -0,0 +1,74 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "crypto" + "encoding/binary" + "io" + "strconv" + + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/s2k" +) + +// OnePassSignature represents a one-pass signature packet. See RFC 4880, +// section 5.4. +type OnePassSignature struct { + SigType SignatureType + Hash crypto.Hash + PubKeyAlgo PublicKeyAlgorithm + KeyId uint64 + IsLast bool +} + +const onePassSignatureVersion = 3 + +func (ops *OnePassSignature) parse(r io.Reader) (err error) { + var buf [13]byte + + _, err = readFull(r, buf[:]) + if err != nil { + return + } + if buf[0] != onePassSignatureVersion { + err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0]))) + } + + var ok bool + ops.Hash, ok = s2k.HashIdToHash(buf[2]) + if !ok { + return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2]))) + } + + ops.SigType = SignatureType(buf[1]) + ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3]) + ops.KeyId = binary.BigEndian.Uint64(buf[4:12]) + ops.IsLast = buf[12] != 0 + return +} + +// Serialize marshals the given OnePassSignature to w. +func (ops *OnePassSignature) Serialize(w io.Writer) error { + var buf [13]byte + buf[0] = onePassSignatureVersion + buf[1] = uint8(ops.SigType) + var ok bool + buf[2], ok = s2k.HashToHashId(ops.Hash) + if !ok { + return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) + } + buf[3] = uint8(ops.PubKeyAlgo) + binary.BigEndian.PutUint64(buf[4:12], ops.KeyId) + if ops.IsLast { + buf[12] = 1 + } + + if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil { + return err + } + _, err := w.Write(buf[:]) + return err +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/opaque.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/opaque.go new file mode 100644 index 000000000..cdeea012f --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/opaque.go @@ -0,0 +1,162 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "bytes" + "io" + "io/ioutil" + + "github.com/keybase/go-crypto/openpgp/errors" +) + +// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is +// useful for splitting and storing the original packet contents separately, +// handling unsupported packet types or accessing parts of the packet not yet +// implemented by this package. +type OpaquePacket struct { + // Packet type + Tag uint8 + // Reason why the packet was parsed opaquely + Reason error + // Binary contents of the packet data + Contents []byte +} + +func (op *OpaquePacket) parse(r io.Reader) (err error) { + op.Contents, err = ioutil.ReadAll(r) + return +} + +// Serialize marshals the packet to a writer in its original form, including +// the packet header. +func (op *OpaquePacket) Serialize(w io.Writer) (err error) { + err = serializeHeader(w, packetType(op.Tag), len(op.Contents)) + if err == nil { + _, err = w.Write(op.Contents) + } + return +} + +// Parse attempts to parse the opaque contents into a structure supported by +// this package. If the packet is not known then the result will be another +// OpaquePacket. +func (op *OpaquePacket) Parse() (p Packet, err error) { + hdr := bytes.NewBuffer(nil) + err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents)) + if err != nil { + op.Reason = err + return op, err + } + p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents))) + if err != nil { + op.Reason = err + p = op + } + return +} + +// OpaqueReader reads OpaquePackets from an io.Reader. +type OpaqueReader struct { + r io.Reader +} + +func NewOpaqueReader(r io.Reader) *OpaqueReader { + return &OpaqueReader{r: r} +} + +// Read the next OpaquePacket. +func (or *OpaqueReader) Next() (op *OpaquePacket, err error) { + tag, _, contents, err := readHeader(or.r) + if err != nil { + return + } + op = &OpaquePacket{Tag: uint8(tag), Reason: err} + err = op.parse(contents) + if err != nil { + consumeAll(contents) + } + return +} + +// OpaqueSubpacket represents an unparsed OpenPGP subpacket, +// as found in signature and user attribute packets. +type OpaqueSubpacket struct { + SubType uint8 + Contents []byte +} + +// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from +// their byte representation. +func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) { + var ( + subHeaderLen int + subPacket *OpaqueSubpacket + ) + for len(contents) > 0 { + subHeaderLen, subPacket, err = nextSubpacket(contents) + if err != nil { + break + } + result = append(result, subPacket) + contents = contents[subHeaderLen+len(subPacket.Contents):] + } + return +} + +func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { + // RFC 4880, section 5.2.3.1 + var subLen uint32 + if len(contents) < 1 { + goto Truncated + } + subPacket = &OpaqueSubpacket{} + switch { + case contents[0] < 192: + subHeaderLen = 2 // 1 length byte, 1 subtype byte + if len(contents) < subHeaderLen { + goto Truncated + } + subLen = uint32(contents[0]) + contents = contents[1:] + case contents[0] < 255: + subHeaderLen = 3 // 2 length bytes, 1 subtype + if len(contents) < subHeaderLen { + goto Truncated + } + subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 + contents = contents[2:] + default: + subHeaderLen = 6 // 5 length bytes, 1 subtype + if len(contents) < subHeaderLen { + goto Truncated + } + subLen = uint32(contents[1])<<24 | + uint32(contents[2])<<16 | + uint32(contents[3])<<8 | + uint32(contents[4]) + contents = contents[5:] + } + if subLen > uint32(len(contents)) || subLen == 0 { + goto Truncated + } + subPacket.SubType = contents[0] + subPacket.Contents = contents[1:subLen] + return +Truncated: + err = errors.StructuralError("subpacket truncated") + return +} + +func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) { + buf := make([]byte, 6) + n := serializeSubpacketLength(buf, len(osp.Contents)+1) + buf[n] = osp.SubType + if _, err = w.Write(buf[:n+1]); err != nil { + return + } + _, err = w.Write(osp.Contents) + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/packet.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/packet.go new file mode 100644 index 000000000..ce6d44007 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/packet.go @@ -0,0 +1,565 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package packet implements parsing and serialization of OpenPGP packets, as +// specified in RFC 4880. +package packet // import "github.com/keybase/go-crypto/openpgp/packet" + +import ( + "bufio" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/elliptic" + "io" + "math/big" + + "github.com/keybase/go-crypto/cast5" + "github.com/keybase/go-crypto/openpgp/errors" +) + +// readFull is the same as io.ReadFull except that reading zero bytes returns +// ErrUnexpectedEOF rather than EOF. +func readFull(r io.Reader, buf []byte) (n int, err error) { + n, err = io.ReadFull(r, buf) + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return +} + +// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2. +func readLength(r io.Reader) (length int64, isPartial bool, err error) { + var buf [4]byte + _, err = readFull(r, buf[:1]) + if err != nil { + return + } + switch { + case buf[0] < 192: + length = int64(buf[0]) + case buf[0] < 224: + length = int64(buf[0]-192) << 8 + _, err = readFull(r, buf[0:1]) + if err != nil { + return + } + length += int64(buf[0]) + 192 + case buf[0] < 255: + length = int64(1) << (buf[0] & 0x1f) + isPartial = true + default: + _, err = readFull(r, buf[0:4]) + if err != nil { + return + } + length = int64(buf[0])<<24 | + int64(buf[1])<<16 | + int64(buf[2])<<8 | + int64(buf[3]) + } + return +} + +// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths. +// The continuation lengths are parsed and removed from the stream and EOF is +// returned at the end of the packet. See RFC 4880, section 4.2.2.4. +type partialLengthReader struct { + r io.Reader + remaining int64 + isPartial bool +} + +func (r *partialLengthReader) Read(p []byte) (n int, err error) { + for r.remaining == 0 { + if !r.isPartial { + return 0, io.EOF + } + r.remaining, r.isPartial, err = readLength(r.r) + if err != nil { + return 0, err + } + } + + toRead := int64(len(p)) + if toRead > r.remaining { + toRead = r.remaining + } + + n, err = r.r.Read(p[:int(toRead)]) + r.remaining -= int64(n) + if n < int(toRead) && err == io.EOF { + err = io.ErrUnexpectedEOF + } + return +} + +// partialLengthWriter writes a stream of data using OpenPGP partial lengths. +// See RFC 4880, section 4.2.2.4. +type partialLengthWriter struct { + w io.WriteCloser + lengthByte [1]byte +} + +func (w *partialLengthWriter) Write(p []byte) (n int, err error) { + for len(p) > 0 { + for power := uint(14); power < 32; power-- { + l := 1 << power + if len(p) >= l { + w.lengthByte[0] = 224 + uint8(power) + _, err = w.w.Write(w.lengthByte[:]) + if err != nil { + return + } + var m int + m, err = w.w.Write(p[:l]) + n += m + if err != nil { + return + } + p = p[l:] + break + } + } + } + return +} + +func (w *partialLengthWriter) Close() error { + w.lengthByte[0] = 0 + _, err := w.w.Write(w.lengthByte[:]) + if err != nil { + return err + } + return w.w.Close() +} + +// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the +// underlying Reader returns EOF before the limit has been reached. +type spanReader struct { + r io.Reader + n int64 +} + +func (l *spanReader) Read(p []byte) (n int, err error) { + if l.n <= 0 { + return 0, io.EOF + } + if int64(len(p)) > l.n { + p = p[0:l.n] + } + n, err = l.r.Read(p) + l.n -= int64(n) + if l.n > 0 && err == io.EOF { + err = io.ErrUnexpectedEOF + } + return +} + +// readHeader parses a packet header and returns an io.Reader which will return +// the contents of the packet. See RFC 4880, section 4.2. +func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) { + var buf [4]byte + _, err = io.ReadFull(r, buf[:1]) + if err != nil { + return + } + if buf[0]&0x80 == 0 { + err = errors.StructuralError("tag byte does not have MSB set") + return + } + if buf[0]&0x40 == 0 { + // Old format packet + tag = packetType((buf[0] & 0x3f) >> 2) + lengthType := buf[0] & 3 + if lengthType == 3 { + length = -1 + contents = r + return + } + lengthBytes := 1 << lengthType + _, err = readFull(r, buf[0:lengthBytes]) + if err != nil { + return + } + for i := 0; i < lengthBytes; i++ { + length <<= 8 + length |= int64(buf[i]) + } + contents = &spanReader{r, length} + return + } + + // New format packet + tag = packetType(buf[0] & 0x3f) + length, isPartial, err := readLength(r) + if err != nil { + return + } + if isPartial { + contents = &partialLengthReader{ + remaining: length, + isPartial: true, + r: r, + } + length = -1 + } else { + contents = &spanReader{r, length} + } + return +} + +// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section +// 4.2. +func serializeHeader(w io.Writer, ptype packetType, length int) (err error) { + var buf [6]byte + var n int + + buf[0] = 0x80 | 0x40 | byte(ptype) + if length < 192 { + buf[1] = byte(length) + n = 2 + } else if length < 8384 { + length -= 192 + buf[1] = 192 + byte(length>>8) + buf[2] = byte(length) + n = 3 + } else { + buf[1] = 255 + buf[2] = byte(length >> 24) + buf[3] = byte(length >> 16) + buf[4] = byte(length >> 8) + buf[5] = byte(length) + n = 6 + } + + _, err = w.Write(buf[:n]) + return +} + +// serializeStreamHeader writes an OpenPGP packet header to w where the +// length of the packet is unknown. It returns a io.WriteCloser which can be +// used to write the contents of the packet. See RFC 4880, section 4.2. +func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) { + var buf [1]byte + buf[0] = 0x80 | 0x40 | byte(ptype) + _, err = w.Write(buf[:]) + if err != nil { + return + } + out = &partialLengthWriter{w: w} + return +} + +// Packet represents an OpenPGP packet. Users are expected to try casting +// instances of this interface to specific packet types. +type Packet interface { + parse(io.Reader) error +} + +// consumeAll reads from the given Reader until error, returning the number of +// bytes read. +func consumeAll(r io.Reader) (n int64, err error) { + var m int + var buf [1024]byte + + for { + m, err = r.Read(buf[:]) + n += int64(m) + if err == io.EOF { + err = nil + return + } + if err != nil { + return + } + } + + panic("unreachable") +} + +// packetType represents the numeric ids of the different OpenPGP packet types. See +// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2 +type packetType uint8 + +const ( + packetTypeEncryptedKey packetType = 1 + packetTypeSignature packetType = 2 + packetTypeSymmetricKeyEncrypted packetType = 3 + packetTypeOnePassSignature packetType = 4 + packetTypePrivateKey packetType = 5 + packetTypePublicKey packetType = 6 + packetTypePrivateSubkey packetType = 7 + packetTypeCompressed packetType = 8 + packetTypeSymmetricallyEncrypted packetType = 9 + packetTypeLiteralData packetType = 11 + packetTypeUserId packetType = 13 + packetTypePublicSubkey packetType = 14 + packetTypeUserAttribute packetType = 17 + packetTypeSymmetricallyEncryptedMDC packetType = 18 +) + +// peekVersion detects the version of a public key packet about to +// be read. A bufio.Reader at the original position of the io.Reader +// is returned. +func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) { + bufr = bufio.NewReader(r) + var verBuf []byte + if verBuf, err = bufr.Peek(1); err != nil { + return + } + ver = verBuf[0] + return +} + +// Read reads a single OpenPGP packet from the given io.Reader. If there is an +// error parsing a packet, the whole packet is consumed from the input. +func Read(r io.Reader) (p Packet, err error) { + tag, _, contents, err := readHeader(r) + if err != nil { + return + } + + switch tag { + case packetTypeEncryptedKey: + p = new(EncryptedKey) + case packetTypeSignature: + var version byte + // Detect signature version + if contents, version, err = peekVersion(contents); err != nil { + return + } + if version < 4 { + p = new(SignatureV3) + } else { + p = new(Signature) + } + case packetTypeSymmetricKeyEncrypted: + p = new(SymmetricKeyEncrypted) + case packetTypeOnePassSignature: + p = new(OnePassSignature) + case packetTypePrivateKey, packetTypePrivateSubkey: + pk := new(PrivateKey) + if tag == packetTypePrivateSubkey { + pk.IsSubkey = true + } + p = pk + case packetTypePublicKey, packetTypePublicSubkey: + var version byte + if contents, version, err = peekVersion(contents); err != nil { + return + } + isSubkey := tag == packetTypePublicSubkey + if version < 4 { + p = &PublicKeyV3{IsSubkey: isSubkey} + } else { + p = &PublicKey{IsSubkey: isSubkey} + } + case packetTypeCompressed: + p = new(Compressed) + case packetTypeSymmetricallyEncrypted: + p = new(SymmetricallyEncrypted) + case packetTypeLiteralData: + p = new(LiteralData) + case packetTypeUserId: + p = new(UserId) + case packetTypeUserAttribute: + p = new(UserAttribute) + case packetTypeSymmetricallyEncryptedMDC: + se := new(SymmetricallyEncrypted) + se.MDC = true + p = se + default: + err = errors.UnknownPacketTypeError(tag) + } + if p != nil { + err = p.parse(contents) + } + if err != nil { + consumeAll(contents) + } + return +} + +// SignatureType represents the different semantic meanings of an OpenPGP +// signature. See RFC 4880, section 5.2.1. +type SignatureType uint8 + +const ( + SigTypeBinary SignatureType = 0 + SigTypeText = 1 + SigTypeGenericCert = 0x10 + SigTypePersonaCert = 0x11 + SigTypeCasualCert = 0x12 + SigTypePositiveCert = 0x13 + SigTypeSubkeyBinding = 0x18 + SigTypePrimaryKeyBinding = 0x19 + SigTypeDirectSignature = 0x1F + SigTypeKeyRevocation = 0x20 + SigTypeSubkeyRevocation = 0x28 + SigTypeIdentityRevocation = 0x30 +) + +// PublicKeyAlgorithm represents the different public key system specified for +// OpenPGP. See +// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12 +type PublicKeyAlgorithm uint8 + +const ( + PubKeyAlgoRSA PublicKeyAlgorithm = 1 + PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 + PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 + PubKeyAlgoElGamal PublicKeyAlgorithm = 16 + PubKeyAlgoDSA PublicKeyAlgorithm = 17 + // RFC 6637, Section 5. + PubKeyAlgoECDH PublicKeyAlgorithm = 18 + PubKeyAlgoECDSA PublicKeyAlgorithm = 19 + + PubKeyAlgoBadElGamal PublicKeyAlgorithm = 20 // Reserved (deprecated, formerly ElGamal Encrypt or Sign) + // RFC -1 + PubKeyAlgoEdDSA PublicKeyAlgorithm = 22 +) + +// CanEncrypt returns true if it's possible to encrypt a message to a public +// key of the given type. +func (pka PublicKeyAlgorithm) CanEncrypt() bool { + switch pka { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal, PubKeyAlgoECDH: + return true + } + return false +} + +// CanSign returns true if it's possible for a public key of the given type to +// sign a message. +func (pka PublicKeyAlgorithm) CanSign() bool { + switch pka { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: + return true + } + return false +} + +// CipherFunction represents the different block ciphers specified for OpenPGP. See +// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 +type CipherFunction uint8 + +const ( + Cipher3DES CipherFunction = 2 + CipherCAST5 CipherFunction = 3 + CipherAES128 CipherFunction = 7 + CipherAES192 CipherFunction = 8 + CipherAES256 CipherFunction = 9 +) + +// KeySize returns the key size, in bytes, of cipher. +func (cipher CipherFunction) KeySize() int { + switch cipher { + case Cipher3DES: + return 24 + case CipherCAST5: + return cast5.KeySize + case CipherAES128: + return 16 + case CipherAES192: + return 24 + case CipherAES256: + return 32 + } + return 0 +} + +// blockSize returns the block size, in bytes, of cipher. +func (cipher CipherFunction) blockSize() int { + switch cipher { + case Cipher3DES: + return des.BlockSize + case CipherCAST5: + return 8 + case CipherAES128, CipherAES192, CipherAES256: + return 16 + } + return 0 +} + +// new returns a fresh instance of the given cipher. +func (cipher CipherFunction) new(key []byte) (block cipher.Block) { + switch cipher { + case Cipher3DES: + block, _ = des.NewTripleDESCipher(key) + case CipherCAST5: + block, _ = cast5.NewCipher(key) + case CipherAES128, CipherAES192, CipherAES256: + block, _ = aes.NewCipher(key) + } + return +} + +// readMPI reads a big integer from r. The bit length returned is the bit +// length that was specified in r. This is preserved so that the integer can be +// reserialized exactly. +func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { + var buf [2]byte + _, err = readFull(r, buf[0:]) + if err != nil { + return + } + bitLength = uint16(buf[0])<<8 | uint16(buf[1]) + numBytes := (int(bitLength) + 7) / 8 + mpi = make([]byte, numBytes) + _, err = readFull(r, mpi) + return +} + +// mpiLength returns the length of the given *big.Int when serialized as an +// MPI. +func mpiLength(n *big.Int) (mpiLengthInBytes int) { + mpiLengthInBytes = 2 /* MPI length */ + mpiLengthInBytes += (n.BitLen() + 7) / 8 + return +} + +// writeMPI serializes a big integer to w. +func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { + _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) + if err == nil { + _, err = w.Write(mpiBytes) + } + return +} + +func WritePaddedBigInt(w io.Writer, length int, X *big.Int) (n int, err error) { + bytes := X.Bytes() + n1, err := w.Write(make([]byte, length-len(bytes))) + if err != nil { + return n1, err + } + n2, err := w.Write(bytes) + if err != nil { + return n2, err + } + return (n1 + n2), err +} + +// Minimum number of bytes to fit the curve coordinates. All +// coordinates have to be 0-padded to this length. +func mpiPointByteLength(curve elliptic.Curve) int { + return (curve.Params().P.BitLen() + 7) / 8 +} + +// writeBig serializes a *big.Int to w. +func writeBig(w io.Writer, i *big.Int) error { + return writeMPI(w, uint16(i.BitLen()), i.Bytes()) +} + +// CompressionAlgo Represents the different compression algorithms +// supported by OpenPGP (except for BZIP2, which is not currently +// supported). See Section 9.3 of RFC 4880. +type CompressionAlgo uint8 + +const ( + CompressionNone CompressionAlgo = 0 + CompressionZIP CompressionAlgo = 1 + CompressionZLIB CompressionAlgo = 2 +) diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go new file mode 100644 index 000000000..27974e782 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/private_key.go @@ -0,0 +1,550 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "bytes" + "crypto/cipher" + "crypto/dsa" + "crypto/ecdsa" + "crypto/sha1" + "fmt" + "io" + "io/ioutil" + "math/big" + "strconv" + "time" + + "github.com/keybase/go-crypto/ed25519" + "github.com/keybase/go-crypto/openpgp/ecdh" + "github.com/keybase/go-crypto/openpgp/elgamal" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/s2k" + "github.com/keybase/go-crypto/rsa" +) + +// PrivateKey represents a possibly encrypted private key. See RFC 4880, +// section 5.5.3. +type PrivateKey struct { + PublicKey + Encrypted bool // if true then the private key is unavailable until Decrypt has been called. + encryptedData []byte + cipher CipherFunction + s2k func(out, in []byte) + PrivateKey interface{} // An *rsa.PrivateKey or *dsa.PrivateKey. + sha1Checksum bool + iv []byte + s2kHeader []byte +} + +type EdDSAPrivateKey struct { + PrivateKey + seed parsedMPI +} + +func (e *EdDSAPrivateKey) Sign(digest []byte) (R, S []byte, err error) { + r := bytes.NewReader(e.seed.bytes) + publicKey, privateKey, err := ed25519.GenerateKey(r) + if err != nil { + return nil, nil, err + } + + if !bytes.Equal(publicKey, e.PublicKey.edk.p.bytes[1:]) { // [1:] because [0] is 0x40 mpi header + return nil, nil, errors.UnsupportedError("EdDSA: Private key does not match public key.") + } + + sig := ed25519.Sign(privateKey, digest) + + sigLen := ed25519.SignatureSize / 2 + return sig[:sigLen], sig[sigLen:], nil +} + +func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey { + pk := new(PrivateKey) + pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey) + pk.PrivateKey = priv + return pk +} + +func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey { + pk := new(PrivateKey) + pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey) + pk.PrivateKey = priv + return pk +} + +func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey { + pk := new(PrivateKey) + pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey) + pk.PrivateKey = priv + return pk +} + +func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey { + pk := new(PrivateKey) + pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey) + pk.PrivateKey = priv + return pk +} + +func (pk *PrivateKey) parse(r io.Reader) (err error) { + err = (&pk.PublicKey).parse(r) + if err != nil { + return + } + var buf [1]byte + _, err = readFull(r, buf[:]) + if err != nil { + return + } + + s2kType := buf[0] + + switch s2kType { + case 0: + pk.s2k = nil + pk.Encrypted = false + case 254, 255: + _, err = readFull(r, buf[:]) + if err != nil { + return + } + pk.cipher = CipherFunction(buf[0]) + pk.Encrypted = true + pk.s2k, err = s2k.Parse(r) + if err != nil { + return + } + if s2kType == 254 { + pk.sha1Checksum = true + } + // S2K == nil implies that we got a "GNU Dummy" S2K. For instance, + // because our master secret key is on a USB key in a vault somewhere. + // In that case, there is no further data to consume here. + if pk.s2k == nil { + pk.Encrypted = false + return + } + default: + return errors.UnsupportedError("deprecated s2k function in private key") + } + if pk.Encrypted { + blockSize := pk.cipher.blockSize() + if blockSize == 0 { + return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher))) + } + pk.iv = make([]byte, blockSize) + _, err = readFull(r, pk.iv) + if err != nil { + return + } + } + + pk.encryptedData, err = ioutil.ReadAll(r) + if err != nil { + return + } + + if !pk.Encrypted { + return pk.parsePrivateKey(pk.encryptedData) + } + + return +} + +func mod64kHash(d []byte) uint16 { + var h uint16 + for _, b := range d { + h += uint16(b) + } + return h +} + +// Encrypt is the counterpart to the Decrypt() method below. It encrypts +// the private key with the provided passphrase. If config is nil, then +// the standard, and sensible, defaults apply. +// +// A key will be derived from the given passphrase using S2K Specifier +// Type 3 (Iterated + Salted, see RFC-4880 Sec. 3.7.1.3). This choice +// is hardcoded in s2k.Serialize(). S2KCount is hardcoded to 0, which is +// equivalent to 65536. And the hash algorithm for key-derivation can be +// set with config. The encrypted PrivateKey, using the algorithm specified +// in config (if provided), is written out to the encryptedData member. +// When Serialize() is called, this encryptedData member will be +// serialized, using S2K Usage value of 254, and thus SHA1 checksum. +func (pk *PrivateKey) Encrypt(passphrase []byte, config *Config) (err error) { + if pk.PrivateKey == nil { + return errors.InvalidArgumentError("there is no private key to encrypt") + } + + pk.sha1Checksum = true + pk.cipher = config.Cipher() + s2kConfig := s2k.Config{ + Hash: config.Hash(), + S2KCount: 0, + } + s2kBuf := bytes.NewBuffer(nil) + derivedKey := make([]byte, pk.cipher.KeySize()) + err = s2k.Serialize(s2kBuf, derivedKey, config.Random(), passphrase, &s2kConfig) + if err != nil { + return err + } + + pk.s2kHeader = s2kBuf.Bytes() + // No good way to set pk.s2k but to call s2k.Parse(), + // even though we have all the information here, but + // most of the functions needed are private to s2k. + pk.s2k, err = s2k.Parse(s2kBuf) + pk.iv = make([]byte, pk.cipher.blockSize()) + if _, err = config.Random().Read(pk.iv); err != nil { + return err + } + + privateKeyBuf := bytes.NewBuffer(nil) + if err = pk.serializePrivateKey(privateKeyBuf); err != nil { + return err + } + + checksum := sha1.Sum(privateKeyBuf.Bytes()) + if _, err = privateKeyBuf.Write(checksum[:]); err != nil { + return err + } + + pkData := privateKeyBuf.Bytes() + block := pk.cipher.new(derivedKey) + pk.encryptedData = make([]byte, len(pkData)) + cfb := cipher.NewCFBEncrypter(block, pk.iv) + cfb.XORKeyStream(pk.encryptedData, pkData) + pk.Encrypted = true + return nil +} + +func (pk *PrivateKey) Serialize(w io.Writer) (err error) { + buf := bytes.NewBuffer(nil) + err = pk.PublicKey.serializeWithoutHeaders(buf) + if err != nil { + return + } + + privateKeyBuf := bytes.NewBuffer(nil) + + if pk.PrivateKey == nil { + _, err = buf.Write([]byte{ + 254, // SHA-1 Convention + 9, // Encryption scheme (AES256) + 101, // GNU Extensions + 2, // Hash value (SHA1) + 'G', 'N', 'U', // "GNU" as a string + 1, // Extension type 1001 (minus 1000) + }) + } else if pk.Encrypted { + _, err = buf.Write([]byte{ + 254, // SHA-1 Convention + byte(pk.cipher), // Encryption scheme + }) + if err != nil { + return err + } + if _, err = buf.Write(pk.s2kHeader); err != nil { + return err + } + if _, err = buf.Write(pk.iv); err != nil { + return err + } + if _, err = privateKeyBuf.Write(pk.encryptedData); err != nil { + return err + } + } else { + buf.WriteByte(0 /* no encryption */) + if err = pk.serializePrivateKey(privateKeyBuf); err != nil { + return err + } + } + + ptype := packetTypePrivateKey + contents := buf.Bytes() + privateKeyBytes := privateKeyBuf.Bytes() + if pk.IsSubkey { + ptype = packetTypePrivateSubkey + } + totalLen := len(contents) + len(privateKeyBytes) + if !pk.Encrypted { + totalLen += 2 + } + err = serializeHeader(w, ptype, totalLen) + if err != nil { + return + } + _, err = w.Write(contents) + if err != nil { + return + } + _, err = w.Write(privateKeyBytes) + if err != nil { + return + } + + if len(privateKeyBytes) > 0 && !pk.Encrypted { + checksum := mod64kHash(privateKeyBytes) + var checksumBytes [2]byte + checksumBytes[0] = byte(checksum >> 8) + checksumBytes[1] = byte(checksum) + _, err = w.Write(checksumBytes[:]) + } + + return +} + +func (pk *PrivateKey) serializePrivateKey(w io.Writer) (err error) { + switch priv := pk.PrivateKey.(type) { + case *rsa.PrivateKey: + err = serializeRSAPrivateKey(w, priv) + case *dsa.PrivateKey: + err = serializeDSAPrivateKey(w, priv) + case *elgamal.PrivateKey: + err = serializeElGamalPrivateKey(w, priv) + case *ecdsa.PrivateKey: + err = serializeECDSAPrivateKey(w, priv) + case *ecdh.PrivateKey: + err = serializeECDHPrivateKey(w, priv) + case *EdDSAPrivateKey: + err = serializeEdDSAPrivateKey(w, priv) + default: + err = errors.InvalidArgumentError("unknown private key type") + } + + return err +} + +func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error { + err := writeBig(w, priv.D) + if err != nil { + return err + } + err = writeBig(w, priv.Primes[1]) + if err != nil { + return err + } + err = writeBig(w, priv.Primes[0]) + if err != nil { + return err + } + return writeBig(w, priv.Precomputed.Qinv) +} + +func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error { + return writeBig(w, priv.X) +} + +func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error { + return writeBig(w, priv.X) +} + +func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error { + return writeBig(w, priv.D) +} + +func serializeECDHPrivateKey(w io.Writer, priv *ecdh.PrivateKey) error { + return writeBig(w, priv.X) +} + +func serializeEdDSAPrivateKey(w io.Writer, priv *EdDSAPrivateKey) error { + return writeMPI(w, priv.seed.bitLength, priv.seed.bytes) +} + +// Decrypt decrypts an encrypted private key using a passphrase. +func (pk *PrivateKey) Decrypt(passphrase []byte) error { + if !pk.Encrypted { + return nil + } + // For GNU Dummy S2K, there's no key here, so don't do anything. + if pk.s2k == nil { + return nil + } + + key := make([]byte, pk.cipher.KeySize()) + pk.s2k(key, passphrase) + block := pk.cipher.new(key) + cfb := cipher.NewCFBDecrypter(block, pk.iv) + + data := make([]byte, len(pk.encryptedData)) + cfb.XORKeyStream(data, pk.encryptedData) + + if pk.sha1Checksum { + if len(data) < sha1.Size { + return errors.StructuralError("truncated private key data") + } + h := sha1.New() + h.Write(data[:len(data)-sha1.Size]) + sum := h.Sum(nil) + if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { + return errors.StructuralError("private key checksum failure") + } + data = data[:len(data)-sha1.Size] + } else { + if len(data) < 2 { + return errors.StructuralError("truncated private key data") + } + var sum uint16 + for i := 0; i < len(data)-2; i++ { + sum += uint16(data[i]) + } + if data[len(data)-2] != uint8(sum>>8) || + data[len(data)-1] != uint8(sum) { + return errors.StructuralError("private key checksum failure") + } + data = data[:len(data)-2] + } + + return pk.parsePrivateKey(data) +} + +func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) { + switch pk.PublicKey.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly: + return pk.parseRSAPrivateKey(data) + case PubKeyAlgoDSA: + return pk.parseDSAPrivateKey(data) + case PubKeyAlgoElGamal: + return pk.parseElGamalPrivateKey(data) + case PubKeyAlgoECDSA: + return pk.parseECDSAPrivateKey(data) + case PubKeyAlgoECDH: + return pk.parseECDHPrivateKey(data) + case PubKeyAlgoEdDSA: + return pk.parseEdDSAPrivateKey(data) + } + panic("impossible") +} + +func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) { + rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey) + rsaPriv := new(rsa.PrivateKey) + rsaPriv.PublicKey = *rsaPub + + buf := bytes.NewBuffer(data) + d, _, err := readMPI(buf) + if err != nil { + return + } + p, _, err := readMPI(buf) + if err != nil { + return + } + q, _, err := readMPI(buf) + if err != nil { + return + } + + rsaPriv.D = new(big.Int).SetBytes(d) + rsaPriv.Primes = make([]*big.Int, 2) + rsaPriv.Primes[0] = new(big.Int).SetBytes(p) + rsaPriv.Primes[1] = new(big.Int).SetBytes(q) + if err := rsaPriv.Validate(); err != nil { + return err + } + rsaPriv.Precompute() + pk.PrivateKey = rsaPriv + pk.Encrypted = false + pk.encryptedData = nil + + return nil +} + +func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) { + dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey) + dsaPriv := new(dsa.PrivateKey) + dsaPriv.PublicKey = *dsaPub + + buf := bytes.NewBuffer(data) + x, _, err := readMPI(buf) + if err != nil { + return + } + + dsaPriv.X = new(big.Int).SetBytes(x) + pk.PrivateKey = dsaPriv + pk.Encrypted = false + pk.encryptedData = nil + + return nil +} + +func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) { + pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey) + priv := new(elgamal.PrivateKey) + priv.PublicKey = *pub + + buf := bytes.NewBuffer(data) + x, _, err := readMPI(buf) + if err != nil { + return + } + + priv.X = new(big.Int).SetBytes(x) + pk.PrivateKey = priv + pk.Encrypted = false + pk.encryptedData = nil + + return nil +} + +func (pk *PrivateKey) parseECDHPrivateKey(data []byte) (err error) { + pub := pk.PublicKey.PublicKey.(*ecdh.PublicKey) + priv := new(ecdh.PrivateKey) + priv.PublicKey = *pub + + buf := bytes.NewBuffer(data) + d, _, err := readMPI(buf) + if err != nil { + return + } + + priv.X = new(big.Int).SetBytes(d) + pk.PrivateKey = priv + pk.Encrypted = false + pk.encryptedData = nil + return nil +} + +func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) { + ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey) + ecdsaPriv := new(ecdsa.PrivateKey) + ecdsaPriv.PublicKey = *ecdsaPub + + buf := bytes.NewBuffer(data) + d, _, err := readMPI(buf) + if err != nil { + return + } + + ecdsaPriv.D = new(big.Int).SetBytes(d) + pk.PrivateKey = ecdsaPriv + pk.Encrypted = false + pk.encryptedData = nil + + return nil +} + +func (pk *PrivateKey) parseEdDSAPrivateKey(data []byte) (err error) { + eddsaPriv := new(EdDSAPrivateKey) + eddsaPriv.PublicKey = pk.PublicKey + + buf := bytes.NewBuffer(data) + eddsaPriv.seed.bytes, eddsaPriv.seed.bitLength, err = readMPI(buf) + if err != nil { + return err + } + + if bLen := len(eddsaPriv.seed.bytes); bLen != 32 { // 32 bytes private part of ed25519 key. + return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA private key length: %d", bLen)) + } + + pk.PrivateKey = eddsaPriv + pk.Encrypted = false + pk.encryptedData = nil + + return nil +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/public_key.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/public_key.go new file mode 100644 index 000000000..5eacc2052 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/public_key.go @@ -0,0 +1,947 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "bytes" + "crypto" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" + "encoding/binary" + "fmt" + "hash" + "io" + "math/big" + "strconv" + "time" + + "github.com/keybase/go-crypto/brainpool" + "github.com/keybase/go-crypto/curve25519" + "github.com/keybase/go-crypto/ed25519" + "github.com/keybase/go-crypto/openpgp/ecdh" + "github.com/keybase/go-crypto/openpgp/elgamal" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/rsa" +) + +var ( + // NIST curve P-256 + oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07} + // NIST curve P-384 + oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22} + // NIST curve P-521 + oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23} + // Brainpool curve P-256r1 + oidCurveP256r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07} + // Brainpool curve P-384r1 + oidCurveP384r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B} + // Brainpool curve P-512r1 + oidCurveP512r1 []byte = []byte{0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D} + // EdDSA + oidEdDSA []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01} + // cv25519 + oidCurve25519 []byte = []byte{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01} +) + +const maxOIDLength = 10 + +// ecdsaKey stores the algorithm-specific fields for ECDSA keys. +// as defined in RFC 6637, Section 9. +type ecdsaKey struct { + // oid contains the OID byte sequence identifying the elliptic curve used + oid []byte + // p contains the elliptic curve point that represents the public key + p parsedMPI +} + +type edDSAkey struct { + ecdsaKey +} + +func copyFrontFill(dst, src []byte, length int) int { + if srcLen := len(src); srcLen < length { + return copy(dst[length-srcLen:], src[:]) + } else { + return copy(dst[:], src[:]) + } +} + +func (e *edDSAkey) Verify(payload []byte, r parsedMPI, s parsedMPI) bool { + const halfSigSize = ed25519.SignatureSize / 2 + var sig [ed25519.SignatureSize]byte + + // NOTE: The first byte is 0x40 - MPI header + // TODO: Maybe clean the code up and use 0x40 as a header when + // reading and keep only actual number in p field. Find out how + // other MPIs are stored. + key := e.p.bytes[1:] + + // Note: it may happen that R + S do not form 64-byte signature buffer that + // ed25519 expects, but because we copy it over to an array of exact size, + // we will always pass correctly sized slice to Verify. Slice too short + // would make ed25519 panic(). + copyFrontFill(sig[:halfSigSize], r.bytes, halfSigSize) + copyFrontFill(sig[halfSigSize:], s.bytes, halfSigSize) + + return ed25519.Verify(key, payload, sig[:]) +} + +// parseOID reads the OID for the curve as defined in RFC 6637, Section 9. +func parseOID(r io.Reader) (oid []byte, err error) { + buf := make([]byte, maxOIDLength) + if _, err = readFull(r, buf[:1]); err != nil { + return + } + oidLen := buf[0] + if int(oidLen) > len(buf) { + err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen))) + return + } + oid = buf[:oidLen] + _, err = readFull(r, oid) + return +} + +func (f *ecdsaKey) parse(r io.Reader) (err error) { + if f.oid, err = parseOID(r); err != nil { + return err + } + f.p.bytes, f.p.bitLength, err = readMPI(r) + return err +} + +func (f *ecdsaKey) serialize(w io.Writer) (err error) { + buf := make([]byte, maxOIDLength+1) + buf[0] = byte(len(f.oid)) + copy(buf[1:], f.oid) + if _, err = w.Write(buf[:len(f.oid)+1]); err != nil { + return + } + return writeMPIs(w, f.p) +} + +func getCurveByOid(oid []byte) elliptic.Curve { + switch { + case bytes.Equal(oid, oidCurveP256): + return elliptic.P256() + case bytes.Equal(oid, oidCurveP384): + return elliptic.P384() + case bytes.Equal(oid, oidCurveP521): + return elliptic.P521() + case bytes.Equal(oid, oidCurveP256r1): + return brainpool.P256r1() + case bytes.Equal(oid, oidCurveP384r1): + return brainpool.P384r1() + case bytes.Equal(oid, oidCurveP512r1): + return brainpool.P512r1() + case bytes.Equal(oid, oidCurve25519): + return curve25519.Cv25519() + default: + return nil + } +} + +func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) { + var c = getCurveByOid(f.oid) + // Curve25519 should not be used in ECDSA. + if c == nil || bytes.Equal(f.oid, oidCurve25519) { + return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) + } + // Note: Unmarshal already checks if point is on curve. + x, y := elliptic.Unmarshal(c, f.p.bytes) + if x == nil { + return nil, errors.UnsupportedError("failed to parse EC point") + } + return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil +} + +func (f *ecdsaKey) newECDH() (*ecdh.PublicKey, error) { + var c = getCurveByOid(f.oid) + if c == nil { + return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid)) + } + // ecdh.Unmarshal handles unmarshaling for all curve types. It + // also checks if point is on curve. + x, y := ecdh.Unmarshal(c, f.p.bytes) + if x == nil { + return nil, errors.UnsupportedError("failed to parse EC point") + } + return &ecdh.PublicKey{Curve: c, X: x, Y: y}, nil +} + +func (f *ecdsaKey) byteLen() int { + return 1 + len(f.oid) + 2 + len(f.p.bytes) +} + +type kdfHashFunction byte +type kdfAlgorithm byte + +// ecdhKdf stores key derivation function parameters +// used for ECDH encryption. See RFC 6637, Section 9. +type ecdhKdf struct { + KdfHash kdfHashFunction + KdfAlgo kdfAlgorithm +} + +func (f *ecdhKdf) parse(r io.Reader) (err error) { + buf := make([]byte, 1) + if _, err = readFull(r, buf); err != nil { + return + } + kdfLen := int(buf[0]) + if kdfLen < 3 { + return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen)) + } + buf = make([]byte, kdfLen) + if _, err = readFull(r, buf); err != nil { + return + } + reserved := int(buf[0]) + f.KdfHash = kdfHashFunction(buf[1]) + f.KdfAlgo = kdfAlgorithm(buf[2]) + if reserved != 0x01 { + return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved)) + } + return +} + +func (f *ecdhKdf) serialize(w io.Writer) (err error) { + buf := make([]byte, 4) + // See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys. + buf[0] = byte(0x03) // Length of the following fields + buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now + buf[2] = byte(f.KdfHash) + buf[3] = byte(f.KdfAlgo) + _, err = w.Write(buf[:]) + return +} + +func (f *ecdhKdf) byteLen() int { + return 4 +} + +// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. +type PublicKey struct { + CreationTime time.Time + PubKeyAlgo PublicKeyAlgorithm + PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey + Fingerprint [20]byte + KeyId uint64 + IsSubkey bool + + n, e, p, q, g, y parsedMPI + + // RFC 6637 fields + ec *ecdsaKey + ecdh *ecdhKdf + + // EdDSA fields (no RFC available), uses ecdsa scaffolding + edk *edDSAkey +} + +// signingKey provides a convenient abstraction over signature verification +// for v3 and v4 public keys. +type signingKey interface { + SerializeSignaturePrefix(io.Writer) + serializeWithoutHeaders(io.Writer) error +} + +func FromBig(n *big.Int) parsedMPI { + return parsedMPI{ + bytes: n.Bytes(), + bitLength: uint16(n.BitLen()), + } +} + +func FromBytes(bytes []byte) parsedMPI { + return parsedMPI{ + bytes: bytes, + bitLength: uint16(8 * len(bytes)), + } +} + +// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. +func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey { + pk := &PublicKey{ + CreationTime: creationTime, + PubKeyAlgo: PubKeyAlgoRSA, + PublicKey: pub, + n: FromBig(pub.N), + e: FromBig(big.NewInt(int64(pub.E))), + } + + pk.setFingerPrintAndKeyId() + return pk +} + +// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey. +func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey { + pk := &PublicKey{ + CreationTime: creationTime, + PubKeyAlgo: PubKeyAlgoDSA, + PublicKey: pub, + p: FromBig(pub.P), + q: FromBig(pub.Q), + g: FromBig(pub.G), + y: FromBig(pub.Y), + } + + pk.setFingerPrintAndKeyId() + return pk +} + +// check EdDSA public key material. +// There is currently no RFC for it, but it doesn't mean it's not +// implemented or in use. +func (e *edDSAkey) check() error { + if !bytes.Equal(e.oid, oidEdDSA) { + return errors.UnsupportedError(fmt.Sprintf("Bad OID for EdDSA key: %v", e.oid)) + } + if bLen := len(e.p.bytes); bLen != 33 { // 32 bytes for ed25519 key and 1 byte for 0x40 header + return errors.UnsupportedError(fmt.Sprintf("Unexpected EdDSA public key length: %d", bLen)) + } + return nil +} + +// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey. +func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey { + pk := &PublicKey{ + CreationTime: creationTime, + PubKeyAlgo: PubKeyAlgoElGamal, + PublicKey: pub, + p: FromBig(pub.P), + g: FromBig(pub.G), + y: FromBig(pub.Y), + } + + pk.setFingerPrintAndKeyId() + return pk +} + +func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey { + pk := &PublicKey{ + CreationTime: creationTime, + PubKeyAlgo: PubKeyAlgoECDSA, + PublicKey: pub, + ec: new(ecdsaKey), + } + switch pub.Curve { + case elliptic.P256(): + pk.ec.oid = oidCurveP256 + case elliptic.P384(): + pk.ec.oid = oidCurveP384 + case elliptic.P521(): + pk.ec.oid = oidCurveP521 + case brainpool.P256r1(): + pk.ec.oid = oidCurveP256r1 + case brainpool.P384r1(): + pk.ec.oid = oidCurveP384r1 + case brainpool.P512r1(): + pk.ec.oid = oidCurveP512r1 + } + pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) + pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes)) + + pk.setFingerPrintAndKeyId() + return pk +} + +func (pk *PublicKey) parse(r io.Reader) (err error) { + // RFC 4880, section 5.5.2 + var buf [6]byte + _, err = readFull(r, buf[:]) + if err != nil { + return + } + if buf[0] != 4 { + return errors.UnsupportedError("public key version") + } + pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) + pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + err = pk.parseRSA(r) + case PubKeyAlgoDSA: + err = pk.parseDSA(r) + case PubKeyAlgoElGamal: + err = pk.parseElGamal(r) + case PubKeyAlgoEdDSA: + pk.edk = new(edDSAkey) + if err = pk.edk.parse(r); err != nil { + return err + } + err = pk.edk.check() + case PubKeyAlgoECDSA: + pk.ec = new(ecdsaKey) + if err = pk.ec.parse(r); err != nil { + return err + } + pk.PublicKey, err = pk.ec.newECDSA() + case PubKeyAlgoECDH: + pk.ec = new(ecdsaKey) + if err = pk.ec.parse(r); err != nil { + return + } + pk.ecdh = new(ecdhKdf) + if err = pk.ecdh.parse(r); err != nil { + return + } + pk.PublicKey, err = pk.ec.newECDH() + case PubKeyAlgoBadElGamal: + // Key has ElGamal format but nil-implementation - it will + // load but it's not possible to do any operations using this + // key. + err = pk.parseElGamal(r) + if err != nil { + pk.PublicKey = nil + } + default: + err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) + } + if err != nil { + return + } + + pk.setFingerPrintAndKeyId() + return +} + +func (pk *PublicKey) setFingerPrintAndKeyId() { + // RFC 4880, section 12.2 + fingerPrint := sha1.New() + pk.SerializeSignaturePrefix(fingerPrint) + pk.serializeWithoutHeaders(fingerPrint) + copy(pk.Fingerprint[:], fingerPrint.Sum(nil)) + pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) +} + +// parseRSA parses RSA public key material from the given Reader. See RFC 4880, +// section 5.5.2. +func (pk *PublicKey) parseRSA(r io.Reader) (err error) { + pk.n.bytes, pk.n.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.e.bytes, pk.e.bitLength, err = readMPI(r) + if err != nil { + return + } + + if len(pk.e.bytes) > 7 { + err = errors.UnsupportedError("large public exponent") + return + } + rsa := &rsa.PublicKey{ + N: new(big.Int).SetBytes(pk.n.bytes), + E: 0, + } + for i := 0; i < len(pk.e.bytes); i++ { + rsa.E <<= 8 + rsa.E |= int64(pk.e.bytes[i]) + } + pk.PublicKey = rsa + return +} + +// parseDSA parses DSA public key material from the given Reader. See RFC 4880, +// section 5.5.2. +func (pk *PublicKey) parseDSA(r io.Reader) (err error) { + pk.p.bytes, pk.p.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.q.bytes, pk.q.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.g.bytes, pk.g.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.y.bytes, pk.y.bitLength, err = readMPI(r) + if err != nil { + return + } + + dsa := new(dsa.PublicKey) + dsa.P = new(big.Int).SetBytes(pk.p.bytes) + dsa.Q = new(big.Int).SetBytes(pk.q.bytes) + dsa.G = new(big.Int).SetBytes(pk.g.bytes) + dsa.Y = new(big.Int).SetBytes(pk.y.bytes) + pk.PublicKey = dsa + return +} + +// parseElGamal parses ElGamal public key material from the given Reader. See +// RFC 4880, section 5.5.2. +func (pk *PublicKey) parseElGamal(r io.Reader) (err error) { + pk.p.bytes, pk.p.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.g.bytes, pk.g.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.y.bytes, pk.y.bitLength, err = readMPI(r) + if err != nil { + return + } + + elgamal := new(elgamal.PublicKey) + elgamal.P = new(big.Int).SetBytes(pk.p.bytes) + elgamal.G = new(big.Int).SetBytes(pk.g.bytes) + elgamal.Y = new(big.Int).SetBytes(pk.y.bytes) + pk.PublicKey = elgamal + return +} + +// SerializeSignaturePrefix writes the prefix for this public key to the given Writer. +// The prefix is used when calculating a signature over this public key. See +// RFC 4880, section 5.2.4. +func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) { + var pLength uint16 + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + pLength += 2 + uint16(len(pk.n.bytes)) + pLength += 2 + uint16(len(pk.e.bytes)) + case PubKeyAlgoDSA: + pLength += 2 + uint16(len(pk.p.bytes)) + pLength += 2 + uint16(len(pk.q.bytes)) + pLength += 2 + uint16(len(pk.g.bytes)) + pLength += 2 + uint16(len(pk.y.bytes)) + case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: + pLength += 2 + uint16(len(pk.p.bytes)) + pLength += 2 + uint16(len(pk.g.bytes)) + pLength += 2 + uint16(len(pk.y.bytes)) + case PubKeyAlgoECDSA: + pLength += uint16(pk.ec.byteLen()) + case PubKeyAlgoECDH: + pLength += uint16(pk.ec.byteLen()) + pLength += uint16(pk.ecdh.byteLen()) + case PubKeyAlgoEdDSA: + pLength += uint16(pk.edk.byteLen()) + default: + panic("unknown public key algorithm") + } + pLength += 6 + h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) + return +} + +func (pk *PublicKey) Serialize(w io.Writer) (err error) { + length := 6 // 6 byte header + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + length += 2 + len(pk.n.bytes) + length += 2 + len(pk.e.bytes) + case PubKeyAlgoDSA: + length += 2 + len(pk.p.bytes) + length += 2 + len(pk.q.bytes) + length += 2 + len(pk.g.bytes) + length += 2 + len(pk.y.bytes) + case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: + length += 2 + len(pk.p.bytes) + length += 2 + len(pk.g.bytes) + length += 2 + len(pk.y.bytes) + case PubKeyAlgoECDSA: + length += pk.ec.byteLen() + case PubKeyAlgoECDH: + length += pk.ec.byteLen() + length += pk.ecdh.byteLen() + case PubKeyAlgoEdDSA: + length += pk.edk.byteLen() + default: + panic("unknown public key algorithm") + } + + packetType := packetTypePublicKey + if pk.IsSubkey { + packetType = packetTypePublicSubkey + } + err = serializeHeader(w, packetType, length) + if err != nil { + return + } + return pk.serializeWithoutHeaders(w) +} + +// serializeWithoutHeaders marshals the PublicKey to w in the form of an +// OpenPGP public key packet, not including the packet header. +func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { + var buf [6]byte + buf[0] = 4 + t := uint32(pk.CreationTime.Unix()) + buf[1] = byte(t >> 24) + buf[2] = byte(t >> 16) + buf[3] = byte(t >> 8) + buf[4] = byte(t) + buf[5] = byte(pk.PubKeyAlgo) + + _, err = w.Write(buf[:]) + if err != nil { + return + } + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + return writeMPIs(w, pk.n, pk.e) + case PubKeyAlgoDSA: + return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) + case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: + return writeMPIs(w, pk.p, pk.g, pk.y) + case PubKeyAlgoECDSA: + return pk.ec.serialize(w) + case PubKeyAlgoEdDSA: + return pk.edk.serialize(w) + case PubKeyAlgoECDH: + if err = pk.ec.serialize(w); err != nil { + return + } + return pk.ecdh.serialize(w) + } + return errors.InvalidArgumentError("bad public-key algorithm") +} + +// CanSign returns true iff this public key can generate signatures +func (pk *PublicKey) CanSign() bool { + return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal +} + +// VerifySignature returns nil iff sig is a valid signature, made by this +// public key, of the data hashed into signed. signed is mutated by this call. +func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) { + if !pk.CanSign() { + return errors.InvalidArgumentError("public key cannot generate signatures") + } + + signed.Write(sig.HashSuffix) + hashBytes := signed.Sum(nil) + + // NOTE(maxtaco) 2016-08-22 + // + // We used to do this: + // + // if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { + // return errors.SignatureError("hash tag doesn't match") + // } + // + // But don't do anything in this case. Some GPGs generate bad + // 2-byte hash prefixes, but GPG also doesn't seem to care on + // import. See BrentMaxwell's key. I think it's safe to disable + // this check! + + if pk.PubKeyAlgo != sig.PubKeyAlgo { + return errors.InvalidArgumentError("public key and signature use different algorithms") + } + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) + err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes) + if err != nil { + return errors.SignatureError("RSA verification failure") + } + return nil + case PubKeyAlgoDSA: + dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey) + // Need to truncate hashBytes to match FIPS 186-3 section 4.6. + subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 + if len(hashBytes) > subgroupSize { + hashBytes = hashBytes[:subgroupSize] + } + if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { + return errors.SignatureError("DSA verification failure") + } + return nil + case PubKeyAlgoECDSA: + ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) + if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.bytes), new(big.Int).SetBytes(sig.ECDSASigS.bytes)) { + return errors.SignatureError("ECDSA verification failure") + } + return nil + case PubKeyAlgoEdDSA: + if !pk.edk.Verify(hashBytes, sig.EdDSASigR, sig.EdDSASigS) { + return errors.SignatureError("EdDSA verification failure") + } + return nil + default: + return errors.SignatureError("Unsupported public key algorithm used in signature") + } + panic("unreachable") +} + +// VerifySignatureV3 returns nil iff sig is a valid signature, made by this +// public key, of the data hashed into signed. signed is mutated by this call. +func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { + if !pk.CanSign() { + return errors.InvalidArgumentError("public key cannot generate signatures") + } + + suffix := make([]byte, 5) + suffix[0] = byte(sig.SigType) + binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) + signed.Write(suffix) + hashBytes := signed.Sum(nil) + + if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { + return errors.SignatureError("hash tag doesn't match") + } + + if pk.PubKeyAlgo != sig.PubKeyAlgo { + return errors.InvalidArgumentError("public key and signature use different algorithms") + } + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) + if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { + return errors.SignatureError("RSA verification failure") + } + return + case PubKeyAlgoDSA: + dsaPublicKey := pk.PublicKey.(*dsa.PublicKey) + // Need to truncate hashBytes to match FIPS 186-3 section 4.6. + subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8 + if len(hashBytes) > subgroupSize { + hashBytes = hashBytes[:subgroupSize] + } + if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { + return errors.SignatureError("DSA verification failure") + } + return nil + default: + panic("shouldn't happen") + } + panic("unreachable") +} + +// keySignatureHash returns a Hash of the message that needs to be signed for +// pk to assert a subkey relationship to signed. +func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { + if !hashFunc.Available() { + return nil, errors.UnsupportedError("hash function") + } + h = hashFunc.New() + + updateKeySignatureHash(pk, signed, h) + + return +} + +// updateKeySignatureHash does the actual hash updates for keySignatureHash. +func updateKeySignatureHash(pk, signed signingKey, h hash.Hash) { + // RFC 4880, section 5.2.4 + pk.SerializeSignaturePrefix(h) + pk.serializeWithoutHeaders(h) + signed.SerializeSignaturePrefix(h) + signed.serializeWithoutHeaders(h) +} + +// VerifyKeySignature returns nil iff sig is a valid signature, made by this +// public key, of signed. +func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error { + h, err := keySignatureHash(pk, signed, sig.Hash) + if err != nil { + return err + } + if err = pk.VerifySignature(h, sig); err != nil { + return err + } + + if sig.FlagSign { + + // BUG(maxtaco) + // + // We should check for more than FlagsSign here, because if + // you read keys.go, we can sometimes use signing subkeys even if they're + // not explicitly flagged as such. However, so doing fails lots of currently + // working tests, so I'm not going to do much here. + // + // In other words, we should have this disjunction in the condition above: + // + // || (!sig.FlagsValid && pk.PubKeyAlgo.CanSign()) { + // + + // Signing subkeys must be cross-signed. See + // https://www.gnupg.org/faq/subkey-cross-certify.html. + if sig.EmbeddedSignature == nil { + return errors.StructuralError("signing subkey is missing cross-signature") + } + // Verify the cross-signature. This is calculated over the same + // data as the main signature, so we cannot just recursively + // call signed.VerifyKeySignature(...) + if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil { + return errors.StructuralError("error while hashing for cross-signature: " + err.Error()) + } + if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil { + return errors.StructuralError("error while verifying cross-signature: " + err.Error()) + } + } + + return nil +} + +func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) { + if !hashFunc.Available() { + return nil, errors.UnsupportedError("hash function") + } + h = hashFunc.New() + + // RFC 4880, section 5.2.4 + pk.SerializeSignaturePrefix(h) + pk.serializeWithoutHeaders(h) + + return +} + +// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this +// public key. +func (pk *PublicKey) VerifyRevocationSignature(revokedKey *PublicKey, sig *Signature) (err error) { + h, err := keyRevocationHash(revokedKey, sig.Hash) + if err != nil { + return err + } + return pk.VerifySignature(h, sig) +} + +type teeHash struct { + h hash.Hash +} + +func (t teeHash) Write(b []byte) (n int, err error) { + fmt.Printf("hash -> %s %+v\n", string(b), b) + return t.h.Write(b) +} +func (t teeHash) Sum(b []byte) []byte { return t.h.Sum(b) } +func (t teeHash) Reset() { t.h.Reset() } +func (t teeHash) Size() int { return t.h.Size() } +func (t teeHash) BlockSize() int { return t.h.BlockSize() } + +// userIdSignatureHash returns a Hash of the message that needs to be signed +// to assert that pk is a valid key for id. +func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) { + if !hashFunc.Available() { + return nil, errors.UnsupportedError("hash function") + } + h = hashFunc.New() + + updateUserIdSignatureHash(id, pk, h) + + return +} + +// updateUserIdSignatureHash does the actual hash updates for +// userIdSignatureHash. +func updateUserIdSignatureHash(id string, pk *PublicKey, h hash.Hash) { + // RFC 4880, section 5.2.4 + pk.SerializeSignaturePrefix(h) + pk.serializeWithoutHeaders(h) + + var buf [5]byte + buf[0] = 0xb4 + buf[1] = byte(len(id) >> 24) + buf[2] = byte(len(id) >> 16) + buf[3] = byte(len(id) >> 8) + buf[4] = byte(len(id)) + h.Write(buf[:]) + h.Write([]byte(id)) + + return +} + +// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this +// public key, that id is the identity of pub. +func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) { + h, err := userIdSignatureHash(id, pub, sig.Hash) + if err != nil { + return err + } + return pk.VerifySignature(h, sig) +} + +// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this +// public key, that id is the identity of pub. +func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) { + h, err := userIdSignatureV3Hash(id, pub, sig.Hash) + if err != nil { + return err + } + return pk.VerifySignatureV3(h, sig) +} + +// KeyIdString returns the public key's fingerprint in capital hex +// (e.g. "6C7EE1B8621CC013"). +func (pk *PublicKey) KeyIdString() string { + return fmt.Sprintf("%X", pk.Fingerprint[12:20]) +} + +// KeyIdShortString returns the short form of public key's fingerprint +// in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). +func (pk *PublicKey) KeyIdShortString() string { + return fmt.Sprintf("%X", pk.Fingerprint[16:20]) +} + +// A parsedMPI is used to store the contents of a big integer, along with the +// bit length that was specified in the original input. This allows the MPI to +// be reserialized exactly. +type parsedMPI struct { + bytes []byte + bitLength uint16 +} + +// writeMPIs is a utility function for serializing several big integers to the +// given Writer. +func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) { + for _, mpi := range mpis { + err = writeMPI(w, mpi.bitLength, mpi.bytes) + if err != nil { + return + } + } + return +} + +// BitLength returns the bit length for the given public key. Used for +// displaying key information, actual buffers and BigInts inside may +// have non-matching different size if the key is invalid. +func (pk *PublicKey) BitLength() (bitLength uint16, err error) { + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + bitLength = pk.n.bitLength + case PubKeyAlgoDSA: + bitLength = pk.p.bitLength + case PubKeyAlgoElGamal, PubKeyAlgoBadElGamal: + bitLength = pk.p.bitLength + case PubKeyAlgoECDH: + ecdhPublicKey := pk.PublicKey.(*ecdh.PublicKey) + bitLength = uint16(ecdhPublicKey.Curve.Params().BitSize) + case PubKeyAlgoECDSA: + ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey) + bitLength = uint16(ecdsaPublicKey.Curve.Params().BitSize) + case PubKeyAlgoEdDSA: + // EdDSA only support ed25519 curves right now, just return + // the length. Also, we don't have any PublicKey.Curve object + // to look the size up from. + bitLength = 256 + default: + err = errors.InvalidArgumentError("bad public-key algorithm") + } + return +} + +func (pk *PublicKey) ErrorIfDeprecated() error { + switch pk.PubKeyAlgo { + case PubKeyAlgoBadElGamal: + return errors.DeprecatedKeyError("ElGamal Encrypt or Sign (algo 20) is deprecated") + default: + return nil + } +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/public_key_v3.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/public_key_v3.go new file mode 100644 index 000000000..52474677b --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/public_key_v3.go @@ -0,0 +1,280 @@ +// 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 packet + +import ( + "crypto" + "crypto/md5" + "encoding/binary" + "fmt" + "hash" + "io" + "math/big" + "strconv" + "time" + + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/rsa" +) + +// PublicKeyV3 represents older, version 3 public keys. These keys are less secure and +// should not be used for signing or encrypting. They are supported here only for +// parsing version 3 key material and validating signatures. +// See RFC 4880, section 5.5.2. +type PublicKeyV3 struct { + CreationTime time.Time + DaysToExpire uint16 + PubKeyAlgo PublicKeyAlgorithm + PublicKey *rsa.PublicKey + Fingerprint [16]byte + KeyId uint64 + IsSubkey bool + + n, e parsedMPI +} + +// newRSAPublicKeyV3 returns a PublicKey that wraps the given rsa.PublicKey. +// Included here for testing purposes only. RFC 4880, section 5.5.2: +// "an implementation MUST NOT generate a V3 key, but MAY accept it." +func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 { + pk := &PublicKeyV3{ + CreationTime: creationTime, + PublicKey: pub, + n: FromBig(pub.N), + e: FromBig(big.NewInt(int64(pub.E))), + } + + pk.setFingerPrintAndKeyId() + return pk +} + +func (pk *PublicKeyV3) parse(r io.Reader) (err error) { + // RFC 4880, section 5.5.2 + var buf [8]byte + if _, err = readFull(r, buf[:]); err != nil { + return + } + if buf[0] < 2 || buf[0] > 3 { + return errors.UnsupportedError("public key version") + } + pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) + pk.DaysToExpire = binary.BigEndian.Uint16(buf[5:7]) + pk.PubKeyAlgo = PublicKeyAlgorithm(buf[7]) + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + err = pk.parseRSA(r) + default: + err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) + } + if err != nil { + return + } + + pk.setFingerPrintAndKeyId() + return +} + +func (pk *PublicKeyV3) setFingerPrintAndKeyId() { + // RFC 4880, section 12.2 + fingerPrint := md5.New() + fingerPrint.Write(pk.n.bytes) + fingerPrint.Write(pk.e.bytes) + fingerPrint.Sum(pk.Fingerprint[:0]) + pk.KeyId = binary.BigEndian.Uint64(pk.n.bytes[len(pk.n.bytes)-8:]) +} + +// parseRSA parses RSA public key material from the given Reader. See RFC 4880, +// section 5.5.2. +func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) { + if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil { + return + } + if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil { + return + } + + // RFC 4880 Section 12.2 requires the low 8 bytes of the + // modulus to form the key id. + if len(pk.n.bytes) < 8 { + return errors.StructuralError("v3 public key modulus is too short") + } + if len(pk.e.bytes) > 7 { + err = errors.UnsupportedError("large public exponent") + return + } + rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)} + for i := 0; i < len(pk.e.bytes); i++ { + rsa.E <<= 8 + rsa.E |= int64(pk.e.bytes[i]) + } + pk.PublicKey = rsa + return +} + +// SerializeSignaturePrefix writes the prefix for this public key to the given Writer. +// The prefix is used when calculating a signature over this public key. See +// RFC 4880, section 5.2.4. +func (pk *PublicKeyV3) SerializeSignaturePrefix(w io.Writer) { + var pLength uint16 + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + pLength += 2 + uint16(len(pk.n.bytes)) + pLength += 2 + uint16(len(pk.e.bytes)) + default: + panic("unknown public key algorithm") + } + pLength += 6 + w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)}) + return +} + +func (pk *PublicKeyV3) Serialize(w io.Writer) (err error) { + length := 8 // 8 byte header + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + length += 2 + len(pk.n.bytes) + length += 2 + len(pk.e.bytes) + default: + panic("unknown public key algorithm") + } + + packetType := packetTypePublicKey + if pk.IsSubkey { + packetType = packetTypePublicSubkey + } + if err = serializeHeader(w, packetType, length); err != nil { + return + } + return pk.serializeWithoutHeaders(w) +} + +// serializeWithoutHeaders marshals the PublicKey to w in the form of an +// OpenPGP public key packet, not including the packet header. +func (pk *PublicKeyV3) serializeWithoutHeaders(w io.Writer) (err error) { + var buf [8]byte + // Version 3 + buf[0] = 3 + // Creation time + t := uint32(pk.CreationTime.Unix()) + buf[1] = byte(t >> 24) + buf[2] = byte(t >> 16) + buf[3] = byte(t >> 8) + buf[4] = byte(t) + // Days to expire + buf[5] = byte(pk.DaysToExpire >> 8) + buf[6] = byte(pk.DaysToExpire) + // Public key algorithm + buf[7] = byte(pk.PubKeyAlgo) + + if _, err = w.Write(buf[:]); err != nil { + return + } + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + return writeMPIs(w, pk.n, pk.e) + } + return errors.InvalidArgumentError("bad public-key algorithm") +} + +// CanSign returns true iff this public key can generate signatures +func (pk *PublicKeyV3) CanSign() bool { + return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly +} + +// VerifySignatureV3 returns nil iff sig is a valid signature, made by this +// public key, of the data hashed into signed. signed is mutated by this call. +func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) { + if !pk.CanSign() { + return errors.InvalidArgumentError("public key cannot generate signatures") + } + + suffix := make([]byte, 5) + suffix[0] = byte(sig.SigType) + binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix())) + signed.Write(suffix) + hashBytes := signed.Sum(nil) + + if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { + return errors.SignatureError("hash tag doesn't match") + } + + if pk.PubKeyAlgo != sig.PubKeyAlgo { + return errors.InvalidArgumentError("public key and signature use different algorithms") + } + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { + return errors.SignatureError("RSA verification failure") + } + return + default: + // V3 public keys only support RSA. + panic("shouldn't happen") + } + panic("unreachable") +} + +// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this +// public key, that id is the identity of pub. +func (pk *PublicKeyV3) VerifyUserIdSignatureV3(id string, pub *PublicKeyV3, sig *SignatureV3) (err error) { + h, err := userIdSignatureV3Hash(id, pk, sig.Hash) + if err != nil { + return err + } + return pk.VerifySignatureV3(h, sig) +} + +// VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this +// public key, of signed. +func (pk *PublicKeyV3) VerifyKeySignatureV3(signed *PublicKeyV3, sig *SignatureV3) (err error) { + h, err := keySignatureHash(pk, signed, sig.Hash) + if err != nil { + return err + } + return pk.VerifySignatureV3(h, sig) +} + +// userIdSignatureV3Hash returns a Hash of the message that needs to be signed +// to assert that pk is a valid key for id. +func userIdSignatureV3Hash(id string, pk signingKey, hfn crypto.Hash) (h hash.Hash, err error) { + if !hfn.Available() { + return nil, errors.UnsupportedError("hash function") + } + h = hfn.New() + + // RFC 4880, section 5.2.4 + pk.SerializeSignaturePrefix(h) + pk.serializeWithoutHeaders(h) + + h.Write([]byte(id)) + + return +} + +// KeyIdString returns the public key's fingerprint in capital hex +// (e.g. "6C7EE1B8621CC013"). +func (pk *PublicKeyV3) KeyIdString() string { + return fmt.Sprintf("%X", pk.KeyId) +} + +// KeyIdShortString returns the short form of public key's fingerprint +// in capital hex, as shown by gpg --list-keys (e.g. "621CC013"). +func (pk *PublicKeyV3) KeyIdShortString() string { + return fmt.Sprintf("%X", pk.KeyId&0xFFFFFFFF) +} + +// BitLength returns the bit length for the given public key. +func (pk *PublicKeyV3) BitLength() (bitLength uint16, err error) { + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + bitLength = pk.n.bitLength + default: + err = errors.InvalidArgumentError("bad public-key algorithm") + } + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/reader.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/reader.go new file mode 100644 index 000000000..957b3b897 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/reader.go @@ -0,0 +1,76 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "io" + + "github.com/keybase/go-crypto/openpgp/errors" +) + +// Reader reads packets from an io.Reader and allows packets to be 'unread' so +// that they result from the next call to Next. +type Reader struct { + q []Packet + readers []io.Reader +} + +// New io.Readers are pushed when a compressed or encrypted packet is processed +// and recursively treated as a new source of packets. However, a carefully +// crafted packet can trigger an infinite recursive sequence of packets. See +// http://mumble.net/~campbell/misc/pgp-quine +// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402 +// This constant limits the number of recursive packets that may be pushed. +const maxReaders = 32 + +// Next returns the most recently unread Packet, or reads another packet from +// the top-most io.Reader. Unknown packet types are skipped. +func (r *Reader) Next() (p Packet, err error) { + if len(r.q) > 0 { + p = r.q[len(r.q)-1] + r.q = r.q[:len(r.q)-1] + return + } + + for len(r.readers) > 0 { + p, err = Read(r.readers[len(r.readers)-1]) + if err == nil { + return + } + if err == io.EOF { + r.readers = r.readers[:len(r.readers)-1] + continue + } + if _, ok := err.(errors.UnknownPacketTypeError); !ok { + return nil, err + } + } + return nil, io.EOF +} + +// Push causes the Reader to start reading from a new io.Reader. When an EOF +// error is seen from the new io.Reader, it is popped and the Reader continues +// to read from the next most recent io.Reader. Push returns a StructuralError +// if pushing the reader would exceed the maximum recursion level, otherwise it +// returns nil. +func (r *Reader) Push(reader io.Reader) (err error) { + if len(r.readers) >= maxReaders { + return errors.StructuralError("too many layers of packets") + } + r.readers = append(r.readers, reader) + return nil +} + +// Unread causes the given Packet to be returned from the next call to Next. +func (r *Reader) Unread(p Packet) { + r.q = append(r.q, p) +} + +func NewReader(r io.Reader) *Reader { + return &Reader{ + q: nil, + readers: []io.Reader{r}, + } +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/signature.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/signature.go new file mode 100644 index 000000000..449e5af17 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/signature.go @@ -0,0 +1,882 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "bytes" + "crypto" + "crypto/dsa" + "crypto/ecdsa" + "encoding/binary" + "hash" + "io" + "strconv" + "time" + + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/s2k" + "github.com/keybase/go-crypto/rsa" +) + +const ( + // See RFC 4880, section 5.2.3.21 for details. + KeyFlagCertify = 1 << iota + KeyFlagSign + KeyFlagEncryptCommunications + KeyFlagEncryptStorage +) + +// Signer can be implemented by application code to do actual signing. +type Signer interface { + hash.Hash + Sign(sig *Signature) error + KeyId() uint64 + PublicKeyAlgo() PublicKeyAlgorithm +} + +// RevocationKey represents designated revoker packet. See RFC 4880 +// section 5.2.3.15 for details. +type RevocationKey struct { + Class byte + PublicKeyAlgo PublicKeyAlgorithm + Fingerprint []byte +} + +// KeyFlagBits holds boolean whether any usage flags were provided in +// the signature and BitField with KeyFlag* flags. +type KeyFlagBits struct { + Valid bool + BitField byte +} + +// Signature represents a signature. See RFC 4880, section 5.2. +type Signature struct { + SigType SignatureType + PubKeyAlgo PublicKeyAlgorithm + Hash crypto.Hash + + // HashSuffix is extra data that is hashed in after the signed data. + HashSuffix []byte + // HashTag contains the first two bytes of the hash for fast rejection + // of bad signed data. + HashTag [2]byte + CreationTime time.Time + + RSASignature parsedMPI + DSASigR, DSASigS parsedMPI + ECDSASigR, ECDSASigS parsedMPI + EdDSASigR, EdDSASigS parsedMPI + + // rawSubpackets contains the unparsed subpackets, in order. + rawSubpackets []outputSubpacket + + // The following are optional so are nil when not included in the + // signature. + + SigLifetimeSecs, KeyLifetimeSecs *uint32 + PreferredSymmetric, PreferredHash, PreferredCompression []uint8 + PreferredKeyServer string + IssuerKeyId *uint64 + IsPrimaryId *bool + IssuerFingerprint []byte + + // FlagsValid is set if any flags were given. See RFC 4880, section + // 5.2.3.21 for details. + FlagsValid bool + FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool + + // RevocationReason is set if this signature has been revoked. + // See RFC 4880, section 5.2.3.23 for details. + RevocationReason *uint8 + RevocationReasonText string + + // PolicyURI is optional. See RFC 4880, Section 5.2.3.20 for details + PolicyURI string + + // Regex is a regex that can match a PGP UID. See RFC 4880, 5.2.3.14 for details + Regex string + + // MDC is set if this signature has a feature packet that indicates + // support for MDC subpackets. + MDC bool + + // EmbeddedSignature, if non-nil, is a signature of the parent key, by + // this key. This prevents an attacker from claiming another's signing + // subkey as their own. + EmbeddedSignature *Signature + + // StubbedOutCriticalError is not fail-stop, since it shouldn't break key parsing + // when appearing in WoT-style cross signatures. But it should prevent a signature + // from being applied to a primary or subkey. + StubbedOutCriticalError error + + // DesignaterRevoker will be present if this signature certifies a + // designated revoking key id (3rd party key that can sign + // revocation for this key). + DesignatedRevoker *RevocationKey + + outSubpackets []outputSubpacket +} + +func (sig *Signature) parse(r io.Reader) (err error) { + // RFC 4880, section 5.2.3 + var buf [5]byte + _, err = readFull(r, buf[:1]) + if err != nil { + return + } + if buf[0] != 4 { + err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) + return + } + + _, err = readFull(r, buf[:5]) + if err != nil { + return + } + sig.SigType = SignatureType(buf[0]) + sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1]) + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA, PubKeyAlgoEdDSA: + default: + err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) + return + } + + var ok bool + sig.Hash, ok = s2k.HashIdToHash(buf[2]) + if !ok { + return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) + } + + hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4]) + l := 6 + hashedSubpacketsLength + sig.HashSuffix = make([]byte, l+6) + sig.HashSuffix[0] = 4 + copy(sig.HashSuffix[1:], buf[:5]) + hashedSubpackets := sig.HashSuffix[6:l] + _, err = readFull(r, hashedSubpackets) + if err != nil { + return + } + // See RFC 4880, section 5.2.4 + trailer := sig.HashSuffix[l:] + trailer[0] = 4 + trailer[1] = 0xff + trailer[2] = uint8(l >> 24) + trailer[3] = uint8(l >> 16) + trailer[4] = uint8(l >> 8) + trailer[5] = uint8(l) + + err = parseSignatureSubpackets(sig, hashedSubpackets, true) + if err != nil { + return + } + + _, err = readFull(r, buf[:2]) + if err != nil { + return + } + unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1]) + unhashedSubpackets := make([]byte, unhashedSubpacketsLength) + _, err = readFull(r, unhashedSubpackets) + if err != nil { + return + } + err = parseSignatureSubpackets(sig, unhashedSubpackets, false) + if err != nil { + return + } + + _, err = readFull(r, sig.HashTag[:2]) + if err != nil { + return + } + + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) + case PubKeyAlgoDSA: + sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) + if err == nil { + sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) + } + case PubKeyAlgoEdDSA: + sig.EdDSASigR.bytes, sig.EdDSASigR.bitLength, err = readMPI(r) + if err == nil { + sig.EdDSASigS.bytes, sig.EdDSASigS.bitLength, err = readMPI(r) + } + case PubKeyAlgoECDSA: + sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r) + if err == nil { + sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r) + } + default: + panic("unreachable") + } + return +} + +// parseSignatureSubpackets parses subpackets of the main signature packet. See +// RFC 4880, section 5.2.3.1. +func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) { + for len(subpackets) > 0 { + subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed) + if err != nil { + return + } + } + + if sig.CreationTime.IsZero() { + err = errors.StructuralError("no creation time in signature") + } + + return +} + +type signatureSubpacketType uint8 + +const ( + creationTimeSubpacket signatureSubpacketType = 2 + signatureExpirationSubpacket signatureSubpacketType = 3 + regularExpressionSubpacket signatureSubpacketType = 6 + keyExpirationSubpacket signatureSubpacketType = 9 + prefSymmetricAlgosSubpacket signatureSubpacketType = 11 + revocationKey signatureSubpacketType = 12 + issuerSubpacket signatureSubpacketType = 16 + prefHashAlgosSubpacket signatureSubpacketType = 21 + prefCompressionSubpacket signatureSubpacketType = 22 + prefKeyServerSubpacket signatureSubpacketType = 24 + primaryUserIdSubpacket signatureSubpacketType = 25 + policyURISubpacket signatureSubpacketType = 26 + keyFlagsSubpacket signatureSubpacketType = 27 + reasonForRevocationSubpacket signatureSubpacketType = 29 + featuresSubpacket signatureSubpacketType = 30 + embeddedSignatureSubpacket signatureSubpacketType = 32 + issuerFingerprint signatureSubpacketType = 33 +) + +// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. +func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) { + // RFC 4880, section 5.2.3.1 + var ( + length uint32 + packetType signatureSubpacketType + isCritical bool + ) + switch { + case subpacket[0] < 192: + length = uint32(subpacket[0]) + subpacket = subpacket[1:] + case subpacket[0] < 255: + if len(subpacket) < 2 { + goto Truncated + } + length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192 + subpacket = subpacket[2:] + default: + if len(subpacket) < 5 { + goto Truncated + } + length = uint32(subpacket[1])<<24 | + uint32(subpacket[2])<<16 | + uint32(subpacket[3])<<8 | + uint32(subpacket[4]) + subpacket = subpacket[5:] + } + if length > uint32(len(subpacket)) { + goto Truncated + } + rest = subpacket[length:] + subpacket = subpacket[:length] + if len(subpacket) == 0 { + err = errors.StructuralError("zero length signature subpacket") + return + } + packetType = signatureSubpacketType(subpacket[0] & 0x7f) + isCritical = subpacket[0]&0x80 == 0x80 + subpacket = subpacket[1:] + sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) + switch packetType { + case creationTimeSubpacket: + if !isHashed { + err = errors.StructuralError("signature creation time in non-hashed area") + return + } + if len(subpacket) != 4 { + err = errors.StructuralError("signature creation time not four bytes") + return + } + t := binary.BigEndian.Uint32(subpacket) + sig.CreationTime = time.Unix(int64(t), 0) + case signatureExpirationSubpacket: + // Signature expiration time, section 5.2.3.10 + if !isHashed { + return + } + if len(subpacket) != 4 { + err = errors.StructuralError("expiration subpacket with bad length") + return + } + sig.SigLifetimeSecs = new(uint32) + *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) + case keyExpirationSubpacket: + // Key expiration time, section 5.2.3.6 + if !isHashed { + return + } + if len(subpacket) != 4 { + err = errors.StructuralError("key expiration subpacket with bad length") + return + } + sig.KeyLifetimeSecs = new(uint32) + *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket) + case prefSymmetricAlgosSubpacket: + // Preferred symmetric algorithms, section 5.2.3.7 + if !isHashed { + return + } + sig.PreferredSymmetric = make([]byte, len(subpacket)) + copy(sig.PreferredSymmetric, subpacket) + case issuerSubpacket: + // Issuer, section 5.2.3.5 + if len(subpacket) != 8 { + err = errors.StructuralError("issuer subpacket with bad length") + return + } + sig.IssuerKeyId = new(uint64) + *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket) + case prefHashAlgosSubpacket: + // Preferred hash algorithms, section 5.2.3.8 + if !isHashed { + return + } + sig.PreferredHash = make([]byte, len(subpacket)) + copy(sig.PreferredHash, subpacket) + case prefCompressionSubpacket: + // Preferred compression algorithms, section 5.2.3.9 + if !isHashed { + return + } + sig.PreferredCompression = make([]byte, len(subpacket)) + copy(sig.PreferredCompression, subpacket) + case primaryUserIdSubpacket: + // Primary User ID, section 5.2.3.19 + if !isHashed { + return + } + if len(subpacket) != 1 { + err = errors.StructuralError("primary user id subpacket with bad length") + return + } + sig.IsPrimaryId = new(bool) + if subpacket[0] > 0 { + *sig.IsPrimaryId = true + } + case keyFlagsSubpacket: + // Key flags, section 5.2.3.21 + if !isHashed { + return + } + if len(subpacket) == 0 { + err = errors.StructuralError("empty key flags subpacket") + return + } + if subpacket[0] != 0 { + sig.FlagsValid = true + if subpacket[0]&KeyFlagCertify != 0 { + sig.FlagCertify = true + } + if subpacket[0]&KeyFlagSign != 0 { + sig.FlagSign = true + } + if subpacket[0]&KeyFlagEncryptCommunications != 0 { + sig.FlagEncryptCommunications = true + } + if subpacket[0]&KeyFlagEncryptStorage != 0 { + sig.FlagEncryptStorage = true + } + } + case reasonForRevocationSubpacket: + // Reason For Revocation, section 5.2.3.23 + if !isHashed { + return + } + if len(subpacket) == 0 { + err = errors.StructuralError("empty revocation reason subpacket") + return + } + sig.RevocationReason = new(uint8) + *sig.RevocationReason = subpacket[0] + sig.RevocationReasonText = string(subpacket[1:]) + case featuresSubpacket: + // Features subpacket, section 5.2.3.24 specifies a very general + // mechanism for OpenPGP implementations to signal support for new + // features. In practice, the subpacket is used exclusively to + // indicate support for MDC-protected encryption. + sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1 + case embeddedSignatureSubpacket: + // Only usage is in signatures that cross-certify + // signing subkeys. section 5.2.3.26 describes the + // format, with its usage described in section 11.1 + if sig.EmbeddedSignature != nil { + err = errors.StructuralError("Cannot have multiple embedded signatures") + return + } + sig.EmbeddedSignature = new(Signature) + // Embedded signatures are required to be v4 signatures see + // section 12.1. However, we only parse v4 signatures in this + // file anyway. + if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil { + return nil, err + } + if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding { + return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType))) + } + case policyURISubpacket: + // See RFC 4880, Section 5.2.3.20 + sig.PolicyURI = string(subpacket[:]) + case regularExpressionSubpacket: + sig.Regex = string(subpacket[:]) + if isCritical { + sig.StubbedOutCriticalError = errors.UnsupportedError("regex support is stubbed out") + } + case prefKeyServerSubpacket: + sig.PreferredKeyServer = string(subpacket[:]) + case issuerFingerprint: + // The first byte is how many bytes the fingerprint is, but we'll just + // read until the end of the subpacket, so we'll ignore it. + sig.IssuerFingerprint = append([]byte{}, subpacket[1:]...) + case revocationKey: + // Authorizes the specified key to issue revocation signatures + // for a key. + + // TODO: Class octet must have bit 0x80 set. If the bit 0x40 + // is set, then this means that the revocation information is + // sensitive. + sig.DesignatedRevoker = &RevocationKey{ + Class: subpacket[0], + PublicKeyAlgo: PublicKeyAlgorithm(subpacket[1]), + Fingerprint: append([]byte{}, subpacket[2:]...), + } + default: + if isCritical { + err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) + return + } + } + return + +Truncated: + err = errors.StructuralError("signature subpacket truncated") + return +} + +// subpacketLengthLength returns the length, in bytes, of an encoded length value. +func subpacketLengthLength(length int) int { + if length < 192 { + return 1 + } + if length < 16320 { + return 2 + } + return 5 +} + +// serializeSubpacketLength marshals the given length into to. +func serializeSubpacketLength(to []byte, length int) int { + // RFC 4880, Section 4.2.2. + if length < 192 { + to[0] = byte(length) + return 1 + } + if length < 16320 { + length -= 192 + to[0] = byte((length >> 8) + 192) + to[1] = byte(length) + return 2 + } + to[0] = 255 + to[1] = byte(length >> 24) + to[2] = byte(length >> 16) + to[3] = byte(length >> 8) + to[4] = byte(length) + return 5 +} + +// subpacketsLength returns the serialized length, in bytes, of the given +// subpackets. +func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) { + for _, subpacket := range subpackets { + if subpacket.hashed == hashed { + length += subpacketLengthLength(len(subpacket.contents) + 1) + length += 1 // type byte + length += len(subpacket.contents) + } + } + return +} + +// serializeSubpackets marshals the given subpackets into to. +func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { + for _, subpacket := range subpackets { + if subpacket.hashed == hashed { + n := serializeSubpacketLength(to, len(subpacket.contents)+1) + to[n] = byte(subpacket.subpacketType) + to = to[1+n:] + n = copy(to, subpacket.contents) + to = to[n:] + } + } + return +} + +// KeyExpired returns whether sig is a self-signature of a key that has +// expired. +func (sig *Signature) KeyExpired(currentTime time.Time) bool { + if sig.KeyLifetimeSecs == nil { + return false + } + expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second) + return currentTime.After(expiry) +} + +// ExpiresBeforeOther checks if other signature has expiration at +// later date than sig. +func (sig *Signature) ExpiresBeforeOther(other *Signature) bool { + if sig.KeyLifetimeSecs == nil { + // This sig never expires, or has infinitely long expiration + // time. + return false + } else if other.KeyLifetimeSecs == nil { + // This sig expires at some non-infinite point, but the other + // sig never expires. + return true + } + + getExpiryDate := func(s *Signature) time.Time { + return s.CreationTime.Add(time.Duration(*s.KeyLifetimeSecs) * time.Second) + } + + return getExpiryDate(other).After(getExpiryDate(sig)) +} + +// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. +func (sig *Signature) buildHashSuffix() (err error) { + hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) + + var ok bool + l := 6 + hashedSubpacketsLen + sig.HashSuffix = make([]byte, l+6) + sig.HashSuffix[0] = 4 + sig.HashSuffix[1] = uint8(sig.SigType) + sig.HashSuffix[2] = uint8(sig.PubKeyAlgo) + sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) + if !ok { + sig.HashSuffix = nil + return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) + } + sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) + sig.HashSuffix[5] = byte(hashedSubpacketsLen) + serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true) + trailer := sig.HashSuffix[l:] + trailer[0] = 4 + trailer[1] = 0xff + trailer[2] = byte(l >> 24) + trailer[3] = byte(l >> 16) + trailer[4] = byte(l >> 8) + trailer[5] = byte(l) + return +} + +func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { + err = sig.buildHashSuffix() + if err != nil { + return + } + + h.Write(sig.HashSuffix) + digest = h.Sum(nil) + copy(sig.HashTag[:], digest) + return +} + +// Sign signs a message with a private key. The hash, h, must contain +// the hash of the message to be signed and will be mutated by this function. +// On success, the signature is stored in sig. Call Serialize to write it out. +// If config is nil, sensible defaults will be used. +func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) { + signer, hashIsSigner := h.(Signer) + + if !hashIsSigner && (priv == nil || priv.PrivateKey == nil) { + err = errors.InvalidArgumentError("attempting to sign with nil PrivateKey") + return + } + + sig.outSubpackets = sig.buildSubpackets() + digest, err := sig.signPrepareHash(h) + if err != nil { + return + } + + if hashIsSigner { + err = signer.Sign(sig) + return + } + + switch priv.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest) + sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) + case PubKeyAlgoDSA: + dsaPriv := priv.PrivateKey.(*dsa.PrivateKey) + + // Need to truncate hashBytes to match FIPS 186-3 section 4.6. + subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8 + if len(digest) > subgroupSize { + digest = digest[:subgroupSize] + } + r, s, err := dsa.Sign(config.Random(), dsaPriv, digest) + if err == nil { + sig.DSASigR.bytes = r.Bytes() + sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) + sig.DSASigS.bytes = s.Bytes() + sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) + } + case PubKeyAlgoECDSA: + r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest) + if err == nil { + sig.ECDSASigR = FromBig(r) + sig.ECDSASigS = FromBig(s) + } + case PubKeyAlgoEdDSA: + r, s, err := priv.PrivateKey.(*EdDSAPrivateKey).Sign(digest) + if err == nil { + sig.EdDSASigR = FromBytes(r) + sig.EdDSASigS = FromBytes(s) + } + default: + err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) + } + + return +} + +// SignUserId computes a signature from priv, asserting that pub is a valid +// key for the identity id. On success, the signature is stored in sig. Call +// Serialize to write it out. +// If config is nil, sensible defaults will be used. +func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error { + h, err := userIdSignatureHash(id, pub, sig.Hash) + if err != nil { + return err + } + return sig.Sign(h, priv, config) +} + +// SignUserIdWithSigner computes a signature from priv, asserting that pub is a +// valid key for the identity id. On success, the signature is stored in sig. +// Call Serialize to write it out. +// If config is nil, sensible defaults will be used. +func (sig *Signature) SignUserIdWithSigner(id string, pub *PublicKey, s Signer, config *Config) error { + updateUserIdSignatureHash(id, pub, s) + + return sig.Sign(s, nil, config) +} + +// SignKey computes a signature from priv, asserting that pub is a subkey. On +// success, the signature is stored in sig. Call Serialize to write it out. +// If config is nil, sensible defaults will be used. +func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error { + h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash) + if err != nil { + return err + } + return sig.Sign(h, priv, config) +} + +// SignKeyWithSigner computes a signature using s, asserting that +// signeePubKey is a subkey. On success, the signature is stored in sig. Call +// Serialize to write it out. If config is nil, sensible defaults will be used. +func (sig *Signature) SignKeyWithSigner(signeePubKey *PublicKey, signerPubKey *PublicKey, s Signer, config *Config) error { + updateKeySignatureHash(signerPubKey, signeePubKey, s) + + return sig.Sign(s, nil, config) +} + +// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been +// called first. +func (sig *Signature) Serialize(w io.Writer) (err error) { + if len(sig.outSubpackets) == 0 { + sig.outSubpackets = sig.rawSubpackets + } + if sig.RSASignature.bytes == nil && + sig.DSASigR.bytes == nil && + sig.ECDSASigR.bytes == nil && + sig.EdDSASigR.bytes == nil { + return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") + } + + sigLength := 0 + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + sigLength = 2 + len(sig.RSASignature.bytes) + case PubKeyAlgoDSA: + sigLength = 2 + len(sig.DSASigR.bytes) + sigLength += 2 + len(sig.DSASigS.bytes) + case PubKeyAlgoEdDSA: + sigLength = 2 + len(sig.EdDSASigR.bytes) + sigLength += 2 + len(sig.EdDSASigS.bytes) + case PubKeyAlgoECDSA: + sigLength = 2 + len(sig.ECDSASigR.bytes) + sigLength += 2 + len(sig.ECDSASigS.bytes) + default: + panic("impossible") + } + + unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false) + length := len(sig.HashSuffix) - 6 /* trailer not included */ + + 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen + + 2 /* hash tag */ + sigLength + err = serializeHeader(w, packetTypeSignature, length) + if err != nil { + return + } + + _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6]) + if err != nil { + return + } + + unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen) + unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8) + unhashedSubpackets[1] = byte(unhashedSubpacketsLen) + serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false) + + _, err = w.Write(unhashedSubpackets) + if err != nil { + return + } + _, err = w.Write(sig.HashTag[:]) + if err != nil { + return + } + + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + err = writeMPIs(w, sig.RSASignature) + case PubKeyAlgoDSA: + err = writeMPIs(w, sig.DSASigR, sig.DSASigS) + case PubKeyAlgoEdDSA: + err = writeMPIs(w, sig.EdDSASigR, sig.EdDSASigS) + case PubKeyAlgoECDSA: + err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS) + default: + panic("impossible") + } + return +} + +// outputSubpacket represents a subpacket to be marshaled. +type outputSubpacket struct { + hashed bool // true if this subpacket is in the hashed area. + subpacketType signatureSubpacketType + isCritical bool + contents []byte +} + +func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { + creationTime := make([]byte, 4) + binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) + subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) + + if sig.IssuerKeyId != nil { + keyId := make([]byte, 8) + binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) + subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) + } + + if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 { + sigLifetime := make([]byte, 4) + binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs) + subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime}) + } + + // Key flags may only appear in self-signatures or certification signatures. + + if sig.FlagsValid { + subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{sig.GetKeyFlags().BitField}}) + } + + // The following subpackets may only appear in self-signatures + + if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 { + keyLifetime := make([]byte, 4) + binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs) + subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime}) + } + + if sig.IsPrimaryId != nil && *sig.IsPrimaryId { + subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}}) + } + + if len(sig.PreferredSymmetric) > 0 { + subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric}) + } + + if len(sig.PreferredHash) > 0 { + subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash}) + } + + if len(sig.PreferredCompression) > 0 { + subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression}) + } + + return +} + +func (sig *Signature) GetKeyFlags() (ret KeyFlagBits) { + if !sig.FlagsValid { + return ret + } + + ret.Valid = true + if sig.FlagCertify { + ret.BitField |= KeyFlagCertify + } + if sig.FlagSign { + ret.BitField |= KeyFlagSign + } + if sig.FlagEncryptCommunications { + ret.BitField |= KeyFlagEncryptCommunications + } + if sig.FlagEncryptStorage { + ret.BitField |= KeyFlagEncryptStorage + } + return ret +} + +func (f *KeyFlagBits) HasFlagCertify() bool { + return f.BitField&KeyFlagCertify != 0 +} + +func (f *KeyFlagBits) HasFlagSign() bool { + return f.BitField&KeyFlagSign != 0 +} + +func (f *KeyFlagBits) HasFlagEncryptCommunications() bool { + return f.BitField&KeyFlagEncryptCommunications != 0 +} + +func (f *KeyFlagBits) HasFlagEncryptStorage() bool { + return f.BitField&KeyFlagEncryptStorage != 0 +} + +func (f *KeyFlagBits) Merge(other KeyFlagBits) { + if other.Valid { + f.Valid = true + f.BitField |= other.BitField + } +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/signature_v3.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/signature_v3.go new file mode 100644 index 000000000..dfca651be --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/signature_v3.go @@ -0,0 +1,146 @@ +// 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 packet + +import ( + "crypto" + "encoding/binary" + "fmt" + "io" + "strconv" + "time" + + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/s2k" +) + +// SignatureV3 represents older version 3 signatures. These signatures are less secure +// than version 4 and should not be used to create new signatures. They are included +// here for backwards compatibility to read and validate with older key material. +// See RFC 4880, section 5.2.2. +type SignatureV3 struct { + SigType SignatureType + CreationTime time.Time + IssuerKeyId uint64 + PubKeyAlgo PublicKeyAlgorithm + Hash crypto.Hash + HashTag [2]byte + + RSASignature parsedMPI + DSASigR, DSASigS parsedMPI +} + +func (sig *SignatureV3) parse(r io.Reader) (err error) { + // RFC 4880, section 5.2.2 + var buf [8]byte + if _, err = readFull(r, buf[:1]); err != nil { + return + } + if buf[0] < 2 || buf[0] > 3 { + err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0]))) + return + } + if _, err = readFull(r, buf[:1]); err != nil { + return + } + if buf[0] != 5 { + err = errors.UnsupportedError( + "invalid hashed material length " + strconv.Itoa(int(buf[0]))) + return + } + + // Read hashed material: signature type + creation time + if _, err = readFull(r, buf[:5]); err != nil { + return + } + sig.SigType = SignatureType(buf[0]) + t := binary.BigEndian.Uint32(buf[1:5]) + sig.CreationTime = time.Unix(int64(t), 0) + + // Eight-octet Key ID of signer. + if _, err = readFull(r, buf[:8]); err != nil { + return + } + sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:]) + + // Public-key and hash algorithm + if _, err = readFull(r, buf[:2]); err != nil { + return + } + sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0]) + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA: + default: + err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo))) + return + } + var ok bool + if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok { + return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2]))) + } + + // Two-octet field holding left 16 bits of signed hash value. + if _, err = readFull(r, sig.HashTag[:2]); err != nil { + return + } + + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) + case PubKeyAlgoDSA: + if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil { + return + } + sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) + default: + panic("unreachable") + } + return +} + +// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been +// called first. +func (sig *SignatureV3) Serialize(w io.Writer) (err error) { + buf := make([]byte, 8) + + // Write the sig type and creation time + buf[0] = byte(sig.SigType) + binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix())) + if _, err = w.Write(buf[:5]); err != nil { + return + } + + // Write the issuer long key ID + binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId) + if _, err = w.Write(buf[:8]); err != nil { + return + } + + // Write public key algorithm, hash ID, and hash value + buf[0] = byte(sig.PubKeyAlgo) + hashId, ok := s2k.HashToHashId(sig.Hash) + if !ok { + return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash)) + } + buf[1] = hashId + copy(buf[2:4], sig.HashTag[:]) + if _, err = w.Write(buf[:4]); err != nil { + return + } + + if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil { + return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize") + } + + switch sig.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + err = writeMPIs(w, sig.RSASignature) + case PubKeyAlgoDSA: + err = writeMPIs(w, sig.DSASigR, sig.DSASigS) + default: + panic("impossible") + } + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/symmetric_key_encrypted.go new file mode 100644 index 000000000..d2bef0ce5 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/symmetric_key_encrypted.go @@ -0,0 +1,158 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "bytes" + "crypto/cipher" + "io" + "strconv" + + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/s2k" +) + +// This is the largest session key that we'll support. Since no 512-bit cipher +// has even been seriously used, this is comfortably large. +const maxSessionKeySizeInBytes = 64 + +// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC +// 4880, section 5.3. +type SymmetricKeyEncrypted struct { + CipherFunc CipherFunction + s2k func(out, in []byte) + encryptedKey []byte +} + +const symmetricKeyEncryptedVersion = 4 + +func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error { + // RFC 4880, section 5.3. + var buf [2]byte + if _, err := readFull(r, buf[:]); err != nil { + return err + } + if buf[0] != symmetricKeyEncryptedVersion { + return errors.UnsupportedError("SymmetricKeyEncrypted version") + } + ske.CipherFunc = CipherFunction(buf[1]) + + if ske.CipherFunc.KeySize() == 0 { + return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) + } + + var err error + ske.s2k, err = s2k.Parse(r) + if err != nil { + return err + } + if ske.s2k == nil { + return errors.UnsupportedError("can't use dummy S2K for symmetric key encryption") + } + + encryptedKey := make([]byte, maxSessionKeySizeInBytes) + // The session key may follow. We just have to try and read to find + // out. If it exists then we limit it to maxSessionKeySizeInBytes. + n, err := readFull(r, encryptedKey) + if err != nil && err != io.ErrUnexpectedEOF { + return err + } + + if n != 0 { + if n == maxSessionKeySizeInBytes { + return errors.UnsupportedError("oversized encrypted session key") + } + ske.encryptedKey = encryptedKey[:n] + } + + return nil +} + +// Decrypt attempts to decrypt an encrypted session key and returns the key and +// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data +// packet. +func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) { + key := make([]byte, ske.CipherFunc.KeySize()) + ske.s2k(key, passphrase) + + if len(ske.encryptedKey) == 0 { + return key, ske.CipherFunc, nil + } + + // the IV is all zeros + iv := make([]byte, ske.CipherFunc.blockSize()) + c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv) + plaintextKey := make([]byte, len(ske.encryptedKey)) + c.XORKeyStream(plaintextKey, ske.encryptedKey) + cipherFunc := CipherFunction(plaintextKey[0]) + if cipherFunc.blockSize() == 0 { + return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) + } + plaintextKey = plaintextKey[1:] + if l := len(plaintextKey); l == 0 || l%cipherFunc.blockSize() != 0 { + return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size") + } + + return plaintextKey, cipherFunc, nil +} + +// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The +// packet contains a random session key, encrypted by a key derived from the +// given passphrase. The session key is returned and must be passed to +// SerializeSymmetricallyEncrypted. +// If config is nil, sensible defaults will be used. +func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) { + cipherFunc := config.Cipher() + keySize := cipherFunc.KeySize() + if keySize == 0 { + return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) + } + + s2kBuf := new(bytes.Buffer) + keyEncryptingKey := make([]byte, keySize) + // s2k.Serialize salts and stretches the passphrase, and writes the + // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. + err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()}) + if err != nil { + return + } + s2kBytes := s2kBuf.Bytes() + + packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize + err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) + if err != nil { + return + } + + var buf [2]byte + buf[0] = symmetricKeyEncryptedVersion + buf[1] = byte(cipherFunc) + _, err = w.Write(buf[:]) + if err != nil { + return + } + _, err = w.Write(s2kBytes) + if err != nil { + return + } + + sessionKey := make([]byte, keySize) + _, err = io.ReadFull(config.Random(), sessionKey) + if err != nil { + return + } + iv := make([]byte, cipherFunc.blockSize()) + c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) + encryptedCipherAndKey := make([]byte, keySize+1) + c.XORKeyStream(encryptedCipherAndKey, buf[1:]) + c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) + _, err = w.Write(encryptedCipherAndKey) + if err != nil { + return + } + + key = sessionKey + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/symmetrically_encrypted.go new file mode 100644 index 000000000..fd4f8f015 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/symmetrically_encrypted.go @@ -0,0 +1,291 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "crypto/cipher" + "crypto/sha1" + "crypto/subtle" + "hash" + "io" + "strconv" + + "github.com/keybase/go-crypto/openpgp/errors" +) + +// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The +// encrypted contents will consist of more OpenPGP packets. See RFC 4880, +// sections 5.7 and 5.13. +type SymmetricallyEncrypted struct { + MDC bool // true iff this is a type 18 packet and thus has an embedded MAC. + contents io.Reader + prefix []byte +} + +const symmetricallyEncryptedVersion = 1 + +func (se *SymmetricallyEncrypted) parse(r io.Reader) error { + if se.MDC { + // See RFC 4880, section 5.13. + var buf [1]byte + _, err := readFull(r, buf[:]) + if err != nil { + return err + } + if buf[0] != symmetricallyEncryptedVersion { + return errors.UnsupportedError("unknown SymmetricallyEncrypted version") + } + } + se.contents = r + return nil +} + +// Decrypt returns a ReadCloser, from which the decrypted contents of the +// packet can be read. An incorrect key can, with high probability, be detected +// immediately and this will result in a KeyIncorrect error being returned. +func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) { + keySize := c.KeySize() + if keySize == 0 { + return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) + } + if len(key) != keySize { + return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length") + } + + if se.prefix == nil { + se.prefix = make([]byte, c.blockSize()+2) + _, err := readFull(se.contents, se.prefix) + if err != nil { + return nil, err + } + } else if len(se.prefix) != c.blockSize()+2 { + return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths") + } + + ocfbResync := OCFBResync + if se.MDC { + // MDC packets use a different form of OCFB mode. + ocfbResync = OCFBNoResync + } + + s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync) + if s == nil { + return nil, errors.ErrKeyIncorrect + } + + plaintext := cipher.StreamReader{S: s, R: se.contents} + + if se.MDC { + // MDC packets have an embedded hash that we need to check. + h := sha1.New() + h.Write(se.prefix) + return &seMDCReader{in: plaintext, h: h}, nil + } + + // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser. + return seReader{plaintext}, nil +} + +// seReader wraps an io.Reader with a no-op Close method. +type seReader struct { + in io.Reader +} + +func (ser seReader) Read(buf []byte) (int, error) { + return ser.in.Read(buf) +} + +func (ser seReader) Close() error { + return nil +} + +const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size + +// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold +// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an +// MDC packet containing a hash of the previous contents which is checked +// against the running hash. See RFC 4880, section 5.13. +type seMDCReader struct { + in io.Reader + h hash.Hash + trailer [mdcTrailerSize]byte + scratch [mdcTrailerSize]byte + trailerUsed int + error bool + eof bool +} + +func (ser *seMDCReader) Read(buf []byte) (n int, err error) { + if ser.error { + err = io.ErrUnexpectedEOF + return + } + if ser.eof { + err = io.EOF + return + } + + // If we haven't yet filled the trailer buffer then we must do that + // first. + for ser.trailerUsed < mdcTrailerSize { + n, err = ser.in.Read(ser.trailer[ser.trailerUsed:]) + ser.trailerUsed += n + if err == io.EOF { + if ser.trailerUsed != mdcTrailerSize { + n = 0 + err = io.ErrUnexpectedEOF + ser.error = true + return + } + ser.eof = true + n = 0 + return + } + + if err != nil { + n = 0 + return + } + } + + // If it's a short read then we read into a temporary buffer and shift + // the data into the caller's buffer. + if len(buf) <= mdcTrailerSize { + n, err = readFull(ser.in, ser.scratch[:len(buf)]) + copy(buf, ser.trailer[:n]) + ser.h.Write(buf[:n]) + copy(ser.trailer[:], ser.trailer[n:]) + copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:]) + if n < len(buf) { + ser.eof = true + err = io.EOF + } + return + } + + n, err = ser.in.Read(buf[mdcTrailerSize:]) + copy(buf, ser.trailer[:]) + ser.h.Write(buf[:n]) + copy(ser.trailer[:], buf[n:]) + + if err == io.EOF { + ser.eof = true + } + return +} + +// This is a new-format packet tag byte for a type 19 (MDC) packet. +const mdcPacketTagByte = byte(0x80) | 0x40 | 19 + +func (ser *seMDCReader) Close() error { + if ser.error { + return errors.SignatureError("error during reading") + } + + for !ser.eof { + // We haven't seen EOF so we need to read to the end + var buf [1024]byte + _, err := ser.Read(buf[:]) + if err == io.EOF { + break + } + if err != nil { + return errors.SignatureError("error during reading") + } + } + + if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { + return errors.SignatureError("MDC packet not found") + } + ser.h.Write(ser.trailer[:2]) + + final := ser.h.Sum(nil) + if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { + return errors.SignatureError("hash mismatch") + } + return nil +} + +// An seMDCWriter writes through to an io.WriteCloser while maintains a running +// hash of the data written. On close, it emits an MDC packet containing the +// running hash. +type seMDCWriter struct { + w io.WriteCloser + h hash.Hash +} + +func (w *seMDCWriter) Write(buf []byte) (n int, err error) { + w.h.Write(buf) + return w.w.Write(buf) +} + +func (w *seMDCWriter) Close() (err error) { + var buf [mdcTrailerSize]byte + + buf[0] = mdcPacketTagByte + buf[1] = sha1.Size + w.h.Write(buf[:2]) + digest := w.h.Sum(nil) + copy(buf[2:], digest) + + _, err = w.w.Write(buf[:]) + if err != nil { + return + } + return w.w.Close() +} + +// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. +type noOpCloser struct { + w io.Writer +} + +func (c noOpCloser) Write(data []byte) (n int, err error) { + return c.w.Write(data) +} + +func (c noOpCloser) Close() error { + return nil +} + +// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet +// to w and returns a WriteCloser to which the to-be-encrypted packets can be +// written. +// If config is nil, sensible defaults will be used. +func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) { + if c.KeySize() != len(key) { + return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") + } + writeCloser := noOpCloser{w} + ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) + if err != nil { + return + } + + _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) + if err != nil { + return + } + + block := c.new(key) + blockSize := block.BlockSize() + iv := make([]byte, blockSize) + _, err = config.Random().Read(iv) + if err != nil { + return + } + s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync) + _, err = ciphertext.Write(prefix) + if err != nil { + return + } + plaintext := cipher.StreamWriter{S: s, W: ciphertext} + + h := sha1.New() + h.Write(iv) + h.Write(iv[blockSize-2:]) + contents = &seMDCWriter{w: plaintext, h: h} + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/userattribute.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/userattribute.go new file mode 100644 index 000000000..96a2b382a --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/userattribute.go @@ -0,0 +1,91 @@ +// 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 packet + +import ( + "bytes" + "image" + "image/jpeg" + "io" + "io/ioutil" +) + +const UserAttrImageSubpacket = 1 + +// UserAttribute is capable of storing other types of data about a user +// beyond name, email and a text comment. In practice, user attributes are typically used +// to store a signed thumbnail photo JPEG image of the user. +// See RFC 4880, section 5.12. +type UserAttribute struct { + Contents []*OpaqueSubpacket +} + +// NewUserAttributePhoto creates a user attribute packet +// containing the given images. +func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) { + uat = new(UserAttribute) + for _, photo := range photos { + var buf bytes.Buffer + // RFC 4880, Section 5.12.1. + data := []byte{ + 0x10, 0x00, // Little-endian image header length (16 bytes) + 0x01, // Image header version 1 + 0x01, // JPEG + 0, 0, 0, 0, // 12 reserved octets, must be all zero. + 0, 0, 0, 0, + 0, 0, 0, 0} + if _, err = buf.Write(data); err != nil { + return + } + if err = jpeg.Encode(&buf, photo, nil); err != nil { + return + } + uat.Contents = append(uat.Contents, &OpaqueSubpacket{ + SubType: UserAttrImageSubpacket, + Contents: buf.Bytes()}) + } + return +} + +// NewUserAttribute creates a new user attribute packet containing the given subpackets. +func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute { + return &UserAttribute{Contents: contents} +} + +func (uat *UserAttribute) parse(r io.Reader) (err error) { + // RFC 4880, section 5.13 + b, err := ioutil.ReadAll(r) + if err != nil { + return + } + uat.Contents, err = OpaqueSubpackets(b) + return +} + +// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including +// header. +func (uat *UserAttribute) Serialize(w io.Writer) (err error) { + var buf bytes.Buffer + for _, sp := range uat.Contents { + sp.Serialize(&buf) + } + if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil { + return err + } + _, err = w.Write(buf.Bytes()) + return +} + +// ImageData returns zero or more byte slices, each containing +// JPEG File Interchange Format (JFIF), for each photo in the +// the user attribute packet. +func (uat *UserAttribute) ImageData() (imageData [][]byte) { + for _, sp := range uat.Contents { + if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { + imageData = append(imageData, sp.Contents[16:]) + } + } + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/packet/userid.go b/vendor/github.com/keybase/go-crypto/openpgp/packet/userid.go new file mode 100644 index 000000000..d6bea7d4a --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/packet/userid.go @@ -0,0 +1,160 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package packet + +import ( + "io" + "io/ioutil" + "strings" +) + +// UserId contains text that is intended to represent the name and email +// address of the key holder. See RFC 4880, section 5.11. By convention, this +// takes the form "Full Name (Comment) " +type UserId struct { + Id string // By convention, this takes the form "Full Name (Comment) " which is split out in the fields below. + + Name, Comment, Email string +} + +func hasInvalidCharacters(s string) bool { + for _, c := range s { + switch c { + case '(', ')', '<', '>', 0: + return true + } + } + return false +} + +// NewUserId returns a UserId or nil if any of the arguments contain invalid +// characters. The invalid characters are '\x00', '(', ')', '<' and '>' +func NewUserId(name, comment, email string) *UserId { + // RFC 4880 doesn't deal with the structure of userid strings; the + // name, comment and email form is just a convention. However, there's + // no convention about escaping the metacharacters and GPG just refuses + // to create user ids where, say, the name contains a '('. We mirror + // this behaviour. + + if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { + return nil + } + + uid := new(UserId) + uid.Name, uid.Comment, uid.Email = name, comment, email + uid.Id = name + if len(comment) > 0 { + if len(uid.Id) > 0 { + uid.Id += " " + } + uid.Id += "(" + uid.Id += comment + uid.Id += ")" + } + if len(email) > 0 { + if len(uid.Id) > 0 { + uid.Id += " " + } + uid.Id += "<" + uid.Id += email + uid.Id += ">" + } + return uid +} + +func (uid *UserId) parse(r io.Reader) (err error) { + // RFC 4880, section 5.11 + b, err := ioutil.ReadAll(r) + if err != nil { + return + } + uid.Id = string(b) + uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id) + return +} + +// Serialize marshals uid to w in the form of an OpenPGP packet, including +// header. +func (uid *UserId) Serialize(w io.Writer) error { + err := serializeHeader(w, packetTypeUserId, len(uid.Id)) + if err != nil { + return err + } + _, err = w.Write([]byte(uid.Id)) + return err +} + +// parseUserId extracts the name, comment and email from a user id string that +// is formatted as "Full Name (Comment) ". +func parseUserId(id string) (name, comment, email string) { + var n, c, e struct { + start, end int + } + var state int + + for offset, rune := range id { + switch state { + case 0: + // Entering name + n.start = offset + state = 1 + fallthrough + case 1: + // In name + if rune == '(' { + state = 2 + n.end = offset + } else if rune == '<' { + state = 5 + n.end = offset + } + case 2: + // Entering comment + c.start = offset + state = 3 + fallthrough + case 3: + // In comment + if rune == ')' { + state = 4 + c.end = offset + } + case 4: + // Between comment and email + if rune == '<' { + state = 5 + } + case 5: + // Entering email + e.start = offset + state = 6 + fallthrough + case 6: + // In email + if rune == '>' { + state = 7 + e.end = offset + } + default: + // After email + } + } + switch state { + case 1: + // ended in the name + n.end = len(id) + case 3: + // ended in comment + c.end = len(id) + case 6: + // ended in email + e.end = len(id) + } + + name = strings.TrimSpace(id[n.start:n.end]) + comment = strings.TrimSpace(id[c.start:c.end]) + email = strings.TrimSpace(id[e.start:e.end]) + return +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/patch.sh b/vendor/github.com/keybase/go-crypto/openpgp/patch.sh new file mode 100644 index 000000000..23cacc83d --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/patch.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +patch < sig-v3.patch +patch < s2k-gnu-dummy.patch +find . -type f -name '*.go' -exec sed -i'' -e 's/golang.org\/x\/crypto\/openpgp/github.com\/keybase\/go-crypto\/openpgp/' {} \; +find . -type f -name '*.go-e' -exec rm {} \; +go test ./... diff --git a/vendor/github.com/keybase/go-crypto/openpgp/read.go b/vendor/github.com/keybase/go-crypto/openpgp/read.go new file mode 100644 index 000000000..790630e55 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/read.go @@ -0,0 +1,500 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package openpgp implements high level operations on OpenPGP messages. +package openpgp // import "github.com/keybase/go-crypto/openpgp" + +import ( + "crypto" + "crypto/hmac" + _ "crypto/sha256" + "hash" + "io" + "strconv" + + "github.com/keybase/go-crypto/openpgp/armor" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/packet" +) + +// SignatureType is the armor type for a PGP signature. +var SignatureType = "PGP SIGNATURE" + +// readArmored reads an armored block with the given type. +func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) { + block, err := armor.Decode(r) + if err != nil { + return + } + + if block.Type != expectedType { + return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type) + } + + return block.Body, nil +} + +// MessageDetails contains the result of parsing an OpenPGP encrypted and/or +// signed message. +type MessageDetails struct { + IsEncrypted bool // true if the message was encrypted. + EncryptedToKeyIds []uint64 // the list of recipient key ids. + IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message. + DecryptedWith Key // the private key used to decrypt the message, if any. + IsSigned bool // true if the message is signed. + SignedByKeyId uint64 // the key id of the signer, if any. + SignedBy *Key // the key of the signer, if available. + LiteralData *packet.LiteralData // the metadata of the contents + UnverifiedBody io.Reader // the contents of the message. + + // If IsSigned is true and SignedBy is non-zero then the signature will + // be verified as UnverifiedBody is read. The signature cannot be + // checked until the whole of UnverifiedBody is read so UnverifiedBody + // must be consumed until EOF before the data can trusted. Even if a + // message isn't signed (or the signer is unknown) the data may contain + // an authentication code that is only checked once UnverifiedBody has + // been consumed. Once EOF has been seen, the following fields are + // valid. (An authentication code failure is reported as a + // SignatureError error when reading from UnverifiedBody.) + SignatureError error // nil if the signature is good. + Signature *packet.Signature // the signature packet itself, if v4 (default) + SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature + + // Does the Message include multiple signatures? Also called "nested signatures". + MultiSig bool + + decrypted io.ReadCloser +} + +// A PromptFunction is used as a callback by functions that may need to decrypt +// a private key, or prompt for a passphrase. It is called with a list of +// acceptable, encrypted private keys and a boolean that indicates whether a +// passphrase is usable. It should either decrypt a private key or return a +// passphrase to try. If the decrypted private key or given passphrase isn't +// correct, the function will be called again, forever. Any error returned will +// be passed up. +type PromptFunction func(keys []Key, symmetric bool) ([]byte, error) + +// A keyEnvelopePair is used to store a private key with the envelope that +// contains a symmetric key, encrypted with that key. +type keyEnvelopePair struct { + key Key + encryptedKey *packet.EncryptedKey +} + +// ReadMessage parses an OpenPGP message that may be signed and/or encrypted. +// The given KeyRing should contain both public keys (for signature +// verification) and, possibly encrypted, private keys for decrypting. +// If config is nil, sensible defaults will be used. +func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) { + var p packet.Packet + + var symKeys []*packet.SymmetricKeyEncrypted + var pubKeys []keyEnvelopePair + var se *packet.SymmetricallyEncrypted + + packets := packet.NewReader(r) + md = new(MessageDetails) + md.IsEncrypted = true + + // The message, if encrypted, starts with a number of packets + // containing an encrypted decryption key. The decryption key is either + // encrypted to a public key, or with a passphrase. This loop + // collects these packets. +ParsePackets: + for { + p, err = packets.Next() + if err != nil { + return nil, err + } + switch p := p.(type) { + case *packet.SymmetricKeyEncrypted: + // This packet contains the decryption key encrypted with a passphrase. + md.IsSymmetricallyEncrypted = true + symKeys = append(symKeys, p) + case *packet.EncryptedKey: + // This packet contains the decryption key encrypted to a public key. + md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) + switch p.Algo { + case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH: + break + default: + continue + } + var keys []Key + if p.KeyId == 0 { + keys = keyring.DecryptionKeys() + } else { + keys = keyring.KeysById(p.KeyId, nil) + } + for _, k := range keys { + pubKeys = append(pubKeys, keyEnvelopePair{k, p}) + } + case *packet.SymmetricallyEncrypted: + se = p + break ParsePackets + case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature: + // This message isn't encrypted. + if len(symKeys) != 0 || len(pubKeys) != 0 { + return nil, errors.StructuralError("key material not followed by encrypted message") + } + packets.Unread(p) + return readSignedMessage(packets, nil, keyring) + } + } + + var candidates []Key + var decrypted io.ReadCloser + + // Now that we have the list of encrypted keys we need to decrypt at + // least one of them or, if we cannot, we need to call the prompt + // function so that it can decrypt a key or give us a passphrase. +FindKey: + for { + // See if any of the keys already have a private key available + candidates = candidates[:0] + candidateFingerprints := make(map[string]bool) + + for _, pk := range pubKeys { + if pk.key.PrivateKey == nil { + continue + } + if !pk.key.PrivateKey.Encrypted { + if len(pk.encryptedKey.Key) == 0 { + pk.encryptedKey.Decrypt(pk.key.PrivateKey, config) + } + if len(pk.encryptedKey.Key) == 0 { + continue + } + decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key) + if err != nil && err != errors.ErrKeyIncorrect { + return nil, err + } + if decrypted != nil { + md.DecryptedWith = pk.key + break FindKey + } + } else { + fpr := string(pk.key.PublicKey.Fingerprint[:]) + if v := candidateFingerprints[fpr]; v { + continue + } + candidates = append(candidates, pk.key) + candidateFingerprints[fpr] = true + } + } + + if len(candidates) == 0 && len(symKeys) == 0 { + return nil, errors.ErrKeyIncorrect + } + + if prompt == nil { + return nil, errors.ErrKeyIncorrect + } + + passphrase, err := prompt(candidates, len(symKeys) != 0) + if err != nil { + return nil, err + } + + // Try the symmetric passphrase first + if len(symKeys) != 0 && passphrase != nil { + for _, s := range symKeys { + key, cipherFunc, err := s.Decrypt(passphrase) + if err == nil { + decrypted, err = se.Decrypt(cipherFunc, key) + if err != nil && err != errors.ErrKeyIncorrect { + return nil, err + } + if decrypted != nil { + break FindKey + } + } + + } + } + } + + md.decrypted = decrypted + if err := packets.Push(decrypted); err != nil { + return nil, err + } + return readSignedMessage(packets, md, keyring) +} + +// readSignedMessage reads a possibly signed message if mdin is non-zero then +// that structure is updated and returned. Otherwise a fresh MessageDetails is +// used. +func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) { + if mdin == nil { + mdin = new(MessageDetails) + } + md = mdin + + var p packet.Packet + var h hash.Hash + var wrappedHash hash.Hash +FindLiteralData: + for { + p, err = packets.Next() + if err != nil { + return nil, err + } + switch p := p.(type) { + case *packet.Compressed: + if err := packets.Push(p.Body); err != nil { + return nil, err + } + case *packet.OnePassSignature: + if md.IsSigned { + // If IsSigned is set, it means we have multiple + // OnePassSignature packets. + md.MultiSig = true + if md.SignedBy != nil { + // We've already found the signature we were looking + // for, made by key that we had in keyring and can + // check signature against. Continue with that instead + // of trying to find another. + continue FindLiteralData + } + } + + h, wrappedHash, err = hashForSignature(p.Hash, p.SigType) + if err != nil { + md = nil + return + } + + md.IsSigned = true + md.SignedByKeyId = p.KeyId + keys := keyring.KeysByIdUsage(p.KeyId, nil, packet.KeyFlagSign) + if len(keys) > 0 { + md.SignedBy = &keys[0] + } + case *packet.LiteralData: + md.LiteralData = p + break FindLiteralData + } + } + + if md.SignedBy != nil { + md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md} + } else if md.decrypted != nil { + md.UnverifiedBody = checkReader{md} + } else { + md.UnverifiedBody = md.LiteralData.Body + } + + return md, nil +} + +// hashForSignature returns a pair of hashes that can be used to verify a +// signature. The signature may specify that the contents of the signed message +// should be preprocessed (i.e. to normalize line endings). Thus this function +// returns two hashes. The second should be used to hash the message itself and +// performs any needed preprocessing. +func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) { + if !hashId.Available() { + return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) + } + h := hashId.New() + + switch sigType { + case packet.SigTypeBinary: + return h, h, nil + case packet.SigTypeText: + return h, NewCanonicalTextHash(h), nil + } + + return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType))) +} + +// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF +// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger +// MDC checks. +type checkReader struct { + md *MessageDetails +} + +func (cr checkReader) Read(buf []byte) (n int, err error) { + n, err = cr.md.LiteralData.Body.Read(buf) + if err == io.EOF { + mdcErr := cr.md.decrypted.Close() + if mdcErr != nil { + err = mdcErr + } + } + return +} + +// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes +// the data as it is read. When it sees an EOF from the underlying io.Reader +// it parses and checks a trailing Signature packet and triggers any MDC checks. +type signatureCheckReader struct { + packets *packet.Reader + h, wrappedHash hash.Hash + md *MessageDetails +} + +func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { + n, err = scr.md.LiteralData.Body.Read(buf) + scr.wrappedHash.Write(buf[:n]) + if err == io.EOF { + for { + var p packet.Packet + p, scr.md.SignatureError = scr.packets.Next() + if scr.md.SignatureError != nil { + if scr.md.MultiSig { + // If we are in MultiSig, we might have found other + // signature that cannot be verified using our key. + // Clear Signature field so it's clear for consumers + // that this message failed to verify. + scr.md.Signature = nil + } + return + } + + var ok bool + if scr.md.Signature, ok = p.(*packet.Signature); ok { + var err error + if keyID := scr.md.Signature.IssuerKeyId; keyID != nil { + if *keyID != scr.md.SignedBy.PublicKey.KeyId { + if scr.md.MultiSig { + continue // try again to find a sig we can verify + } + err = errors.StructuralError("bad key id") + } + } + if fingerprint := scr.md.Signature.IssuerFingerprint; fingerprint != nil { + if !hmac.Equal(fingerprint, scr.md.SignedBy.PublicKey.Fingerprint[:]) { + if scr.md.MultiSig { + continue // try again to find a sig we can verify + } + err = errors.StructuralError("bad key fingerprint") + } + } + if err == nil { + err = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) + } + scr.md.SignatureError = err + } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { + scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) + } else { + scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") + return + } + + // Parse only one packet by default, unless message is MultiSig. Then + // we ask for more packets after discovering non-matching signature, + // until we find one that we can verify. + break + } + + // The SymmetricallyEncrypted packet, if any, might have an + // unsigned hash of its own. In order to check this we need to + // close that Reader. + if scr.md.decrypted != nil { + mdcErr := scr.md.decrypted.Close() + if mdcErr != nil { + err = mdcErr + } + } + } + return +} + +// CheckDetachedSignature takes a signed file and a detached signature and +// returns the signer if the signature is valid. If the signer isn't known, +// ErrUnknownIssuer is returned. +func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { + signer, _, err = checkDetachedSignature(keyring, signed, signature) + return signer, err +} + +func checkDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { + var issuerKeyId uint64 + var issuerFingerprint []byte + var hashFunc crypto.Hash + var sigType packet.SignatureType + var keys []Key + var p packet.Packet + + packets := packet.NewReader(signature) + for { + p, err = packets.Next() + if err == io.EOF { + return nil, nil, errors.ErrUnknownIssuer + } + if err != nil { + return nil, nil, err + } + + switch sig := p.(type) { + case *packet.Signature: + if sig.IssuerKeyId == nil { + return nil, nil, errors.StructuralError("signature doesn't have an issuer") + } + issuerKeyId = *sig.IssuerKeyId + hashFunc = sig.Hash + sigType = sig.SigType + issuerFingerprint = sig.IssuerFingerprint + case *packet.SignatureV3: + issuerKeyId = sig.IssuerKeyId + hashFunc = sig.Hash + sigType = sig.SigType + default: + return nil, nil, errors.StructuralError("non signature packet found") + } + + keys = keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign) + if len(keys) > 0 { + break + } + } + + if len(keys) == 0 { + panic("unreachable") + } + + h, wrappedHash, err := hashForSignature(hashFunc, sigType) + if err != nil { + return nil, nil, err + } + + if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF { + return nil, nil, err + } + + for _, key := range keys { + switch sig := p.(type) { + case *packet.Signature: + err = key.PublicKey.VerifySignature(h, sig) + case *packet.SignatureV3: + err = key.PublicKey.VerifySignatureV3(h, sig) + default: + panic("unreachable") + } + + if err == nil { + return key.Entity, &issuerKeyId, nil + } + } + + return nil, nil, err +} + +// CheckArmoredDetachedSignature performs the same actions as +// CheckDetachedSignature but expects the signature to be armored. +func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) { + signer, _, err = checkArmoredDetachedSignature(keyring, signed, signature) + return signer, err +} + +func checkArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, issuer *uint64, err error) { + body, err := readArmored(signature, SignatureType) + if err != nil { + return + } + return checkDetachedSignature(keyring, signed, body) +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/s2k/s2k.go b/vendor/github.com/keybase/go-crypto/openpgp/s2k/s2k.go new file mode 100644 index 000000000..01bb67852 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/s2k/s2k.go @@ -0,0 +1,326 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package s2k implements the various OpenPGP string-to-key transforms as +// specified in RFC 4800 section 3.7.1. +package s2k // import "github.com/keybase/go-crypto/openpgp/s2k" + +import ( + "crypto" + "hash" + "io" + "strconv" + + "github.com/keybase/go-crypto/openpgp/errors" +) + +// Config collects configuration parameters for s2k key-stretching +// transformatioms. A nil *Config is valid and results in all default +// values. Currently, Config is used only by the Serialize function in +// this package. +type Config struct { + // Hash is the default hash function to be used. If + // nil, SHA1 is used. + Hash crypto.Hash + // S2KCount is only used for symmetric encryption. It + // determines the strength of the passphrase stretching when + // the said passphrase is hashed to produce a key. S2KCount + // should be between 1024 and 65011712, inclusive. If Config + // is nil or S2KCount is 0, the value 65536 used. Not all + // values in the above range can be represented. S2KCount will + // be rounded up to the next representable value if it cannot + // be encoded exactly. When set, it is strongly encrouraged to + // use a value that is at least 65536. See RFC 4880 Section + // 3.7.1.3. + S2KCount int +} + +func (c *Config) hash() crypto.Hash { + if c == nil || uint(c.Hash) == 0 { + // SHA1 is the historical default in this package. + return crypto.SHA1 + } + + return c.Hash +} + +func (c *Config) encodedCount() uint8 { + if c == nil || c.S2KCount == 0 { + return 96 // The common case. Correspoding to 65536 + } + + i := c.S2KCount + switch { + // Behave like GPG. Should we make 65536 the lowest value used? + case i < 1024: + i = 1024 + case i > 65011712: + i = 65011712 + } + + return encodeCount(i) +} + +// encodeCount converts an iterative "count" in the range 1024 to +// 65011712, inclusive, to an encoded count. The return value is the +// octet that is actually stored in the GPG file. encodeCount panics +// if i is not in the above range (encodedCount above takes care to +// pass i in the correct range). See RFC 4880 Section 3.7.7.1. +func encodeCount(i int) uint8 { + if i < 1024 || i > 65011712 { + panic("count arg i outside the required range") + } + + for encoded := 0; encoded < 256; encoded++ { + count := decodeCount(uint8(encoded)) + if count >= i { + return uint8(encoded) + } + } + + return 255 +} + +// decodeCount returns the s2k mode 3 iterative "count" corresponding to +// the encoded octet c. +func decodeCount(c uint8) int { + return (16 + int(c&15)) << (uint32(c>>4) + 6) +} + +// Simple writes to out the result of computing the Simple S2K function (RFC +// 4880, section 3.7.1.1) using the given hash and input passphrase. +func Simple(out []byte, h hash.Hash, in []byte) { + Salted(out, h, in, nil) +} + +var zero [1]byte + +// Salted writes to out the result of computing the Salted S2K function (RFC +// 4880, section 3.7.1.2) using the given hash, input passphrase and salt. +func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { + done := 0 + var digest []byte + + for i := 0; done < len(out); i++ { + h.Reset() + for j := 0; j < i; j++ { + h.Write(zero[:]) + } + h.Write(salt) + h.Write(in) + digest = h.Sum(digest[:0]) + n := copy(out[done:], digest) + done += n + } +} + +// Iterated writes to out the result of computing the Iterated and Salted S2K +// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase, +// salt and iteration count. +func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { + combined := make([]byte, len(in)+len(salt)) + copy(combined, salt) + copy(combined[len(salt):], in) + + if count < len(combined) { + count = len(combined) + } + + done := 0 + var digest []byte + for i := 0; done < len(out); i++ { + h.Reset() + for j := 0; j < i; j++ { + h.Write(zero[:]) + } + written := 0 + for written < count { + if written+len(combined) > count { + todo := count - written + h.Write(combined[:todo]) + written = count + } else { + h.Write(combined) + written += len(combined) + } + } + digest = h.Sum(digest[:0]) + n := copy(out[done:], digest) + done += n + } +} + +func parseGNUExtensions(r io.Reader) (f func(out, in []byte), err error) { + var buf [9]byte + + // A three-byte string identifier + _, err = io.ReadFull(r, buf[:3]) + if err != nil { + return + } + gnuExt := string(buf[:3]) + + if gnuExt != "GNU" { + return nil, errors.UnsupportedError("Malformed GNU extension: " + gnuExt) + } + _, err = io.ReadFull(r, buf[:1]) + if err != nil { + return + } + gnuExtType := int(buf[0]) + switch gnuExtType { + case 1: + return nil, nil + case 2: + // Read a serial number, which is prefixed by a 1-byte length. + // The maximum length is 16. + var lenBuf [1]byte + _, err = io.ReadFull(r, lenBuf[:]) + if err != nil { + return + } + + maxLen := 16 + ivLen := int(lenBuf[0]) + if ivLen > maxLen { + ivLen = maxLen + } + ivBuf := make([]byte, ivLen) + // For now we simply discard the IV + _, err = io.ReadFull(r, ivBuf) + if err != nil { + return + } + return nil, nil + default: + return nil, errors.UnsupportedError("unknown S2K GNU protection mode: " + strconv.Itoa(int(gnuExtType))) + } +} + +// Parse reads a binary specification for a string-to-key transformation from r +// and returns a function which performs that transform. +func Parse(r io.Reader) (f func(out, in []byte), err error) { + var buf [9]byte + + _, err = io.ReadFull(r, buf[:2]) + if err != nil { + return + } + + // GNU Extensions; handle them before we try to look for a hash, which won't + // be needed in most cases anyway. + if buf[0] == 101 { + return parseGNUExtensions(r) + } + + hash, ok := HashIdToHash(buf[1]) + if !ok { + return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1]))) + } + if !hash.Available() { + return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash))) + } + h := hash.New() + + switch buf[0] { + case 0: + f := func(out, in []byte) { + Simple(out, h, in) + } + return f, nil + case 1: + _, err = io.ReadFull(r, buf[:8]) + if err != nil { + return + } + f := func(out, in []byte) { + Salted(out, h, in, buf[:8]) + } + return f, nil + case 3: + _, err = io.ReadFull(r, buf[:9]) + if err != nil { + return + } + count := decodeCount(buf[8]) + f := func(out, in []byte) { + Iterated(out, h, in, buf[:8], count) + } + return f, nil + } + + return nil, errors.UnsupportedError("S2K function") +} + +// Serialize salts and stretches the given passphrase and writes the +// resulting key into key. It also serializes an S2K descriptor to +// w. The key stretching can be configured with c, which may be +// nil. In that case, sensible defaults will be used. +func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error { + var buf [11]byte + buf[0] = 3 /* iterated and salted */ + buf[1], _ = HashToHashId(c.hash()) + salt := buf[2:10] + if _, err := io.ReadFull(rand, salt); err != nil { + return err + } + encodedCount := c.encodedCount() + count := decodeCount(encodedCount) + buf[10] = encodedCount + if _, err := w.Write(buf[:]); err != nil { + return err + } + + Iterated(key, c.hash().New(), passphrase, salt, count) + return nil +} + +// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with +// Go's crypto.Hash type. See RFC 4880, section 9.4. +var hashToHashIdMapping = []struct { + id byte + hash crypto.Hash + name string +}{ + {1, crypto.MD5, "MD5"}, + {2, crypto.SHA1, "SHA1"}, + {3, crypto.RIPEMD160, "RIPEMD160"}, + {8, crypto.SHA256, "SHA256"}, + {9, crypto.SHA384, "SHA384"}, + {10, crypto.SHA512, "SHA512"}, + {11, crypto.SHA224, "SHA224"}, +} + +// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP +// hash id. +func HashIdToHash(id byte) (h crypto.Hash, ok bool) { + for _, m := range hashToHashIdMapping { + if m.id == id { + return m.hash, true + } + } + return 0, false +} + +// HashIdToString returns the name of the hash function corresponding to the +// given OpenPGP hash id, or panics if id is unknown. +func HashIdToString(id byte) (name string, ok bool) { + for _, m := range hashToHashIdMapping { + if m.id == id { + return m.name, true + } + } + + return "", false +} + +// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash. +func HashToHashId(h crypto.Hash) (id byte, ok bool) { + for _, m := range hashToHashIdMapping { + if m.hash == h { + return m.id, true + } + } + return 0, false +} diff --git a/vendor/github.com/keybase/go-crypto/openpgp/sig-v3.patch b/vendor/github.com/keybase/go-crypto/openpgp/sig-v3.patch new file mode 100644 index 000000000..bfd764afe --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/sig-v3.patch @@ -0,0 +1,135 @@ +diff --git a/openpgp/read.go b/openpgp/read.go +index a6cecc5..0c9397b 100644 +--- a/openpgp/read.go ++++ b/openpgp/read.go +@@ -56,8 +56,9 @@ type MessageDetails struct { + // been consumed. Once EOF has been seen, the following fields are + // valid. (An authentication code failure is reported as a + // SignatureError error when reading from UnverifiedBody.) +- SignatureError error // nil if the signature is good. +- Signature *packet.Signature // the signature packet itself. ++ SignatureError error // nil if the signature is good. ++ Signature *packet.Signature // the signature packet itself, if v4 (default) ++ SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature + + decrypted io.ReadCloser + } +@@ -334,13 +335,15 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) { + } + + var ok bool +- if scr.md.Signature, ok = p.(*packet.Signature); !ok { ++ if scr.md.Signature, ok = p.(*packet.Signature); ok { ++ scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) ++ } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok { ++ scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3) ++ } else { + scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature") + return + } + +- scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature) +- + // The SymmetricallyEncrypted packet, if any, might have an + // unsigned hash of its own. In order to check this we need to + // close that Reader. +diff --git a/openpgp/read_test.go b/openpgp/read_test.go +index 52f942c..abe8d7b 100644 +--- a/openpgp/read_test.go ++++ b/openpgp/read_test.go +@@ -13,6 +13,7 @@ import ( + "strings" + "testing" + ++ "golang.org/x/crypto/openpgp/armor" + "golang.org/x/crypto/openpgp/errors" + ) + +@@ -411,6 +412,50 @@ func TestIssue11504(t *testing.T) { + testReadMessageError(t, "9303000130303030303030303030983002303030303030030000000130") + } + ++// TestSignatureV3Message tests the verification of V3 signature, generated ++// with a modern V4-style key. Some people have their clients set to generate ++// V3 signatures, so it's useful to be able to verify them. ++func TestSignatureV3Message(t *testing.T) { ++ sig, err := armor.Decode(strings.NewReader(signedMessageV3)) ++ if err != nil { ++ t.Error(err) ++ return ++ } ++ key, err := ReadArmoredKeyRing(strings.NewReader(keyV4forVerifyingSignedMessageV3)) ++ if err != nil { ++ t.Error(err) ++ return ++ } ++ md, err := ReadMessage(sig.Body, key, nil, nil) ++ if err != nil { ++ t.Error(err) ++ return ++ } ++ ++ _, err = ioutil.ReadAll(md.UnverifiedBody) ++ if err != nil { ++ t.Error(err) ++ return ++ } ++ ++ // We'll see a sig error here after reading in the UnverifiedBody above, ++ // if there was one to see. ++ if err = md.SignatureError; err != nil { ++ t.Error(err) ++ return ++ } ++ ++ if md.SignatureV3 == nil { ++ t.Errorf("No available signature after checking signature") ++ return ++ } ++ if md.Signature != nil { ++ t.Errorf("Did not expect a signature V4 back") ++ return ++ } ++ return ++} ++ + const testKey1KeyId = 0xA34D7E18C20C31BB + const testKey3KeyId = 0x338934250CCC0360 + +@@ -504,3 +549,36 @@ const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6 + const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101` + + const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000` ++ ++const keyV4forVerifyingSignedMessageV3 = `-----BEGIN PGP PUBLIC KEY BLOCK----- ++Comment: GPGTools - https://gpgtools.org ++ ++mI0EVfxoFQEEAMBIqmbDfYygcvP6Phr1wr1XI41IF7Qixqybs/foBF8qqblD9gIY ++BKpXjnBOtbkcVOJ0nljd3/sQIfH4E0vQwK5/4YRQSI59eKOqd6Fx+fWQOLG+uu6z ++tewpeCj9LLHvibx/Sc7VWRnrznia6ftrXxJ/wHMezSab3tnGC0YPVdGNABEBAAG0 ++JEdvY3J5cHRvIFRlc3QgS2V5IDx0aGVtYXhAZ21haWwuY29tPoi5BBMBCgAjBQJV ++/GgVAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQeXnQmhdGW9PFVAP+ ++K7TU0qX5ArvIONIxh/WAweyOk884c5cE8f+3NOPOOCRGyVy0FId5A7MmD5GOQh4H ++JseOZVEVCqlmngEvtHZb3U1VYtVGE5WZ+6rQhGsMcWP5qaT4soYwMBlSYxgYwQcx ++YhN9qOr292f9j2Y//TTIJmZT4Oa+lMxhWdqTfX+qMgG4jQRV/GgVAQQArhFSiij1 ++b+hT3dnapbEU+23Z1yTu1DfF6zsxQ4XQWEV3eR8v+8mEDDNcz8oyyF56k6UQ3rXi ++UMTIwRDg4V6SbZmaFbZYCOwp/EmXJ3rfhm7z7yzXj2OFN22luuqbyVhuL7LRdB0M ++pxgmjXb4tTvfgKd26x34S+QqUJ7W6uprY4sAEQEAAYifBBgBCgAJBQJV/GgVAhsM ++AAoJEHl50JoXRlvT7y8D/02ckx4OMkKBZo7viyrBw0MLG92i+DC2bs35PooHR6zz ++786mitjOp5z2QWNLBvxC70S0qVfCIz8jKupO1J6rq6Z8CcbLF3qjm6h1omUBf8Nd ++EfXKD2/2HV6zMKVknnKzIEzauh+eCKS2CeJUSSSryap/QLVAjRnckaES/OsEWhNB ++=RZia ++-----END PGP PUBLIC KEY BLOCK----- ++` ++ ++const signedMessageV3 = `-----BEGIN PGP MESSAGE----- ++Comment: GPGTools - https://gpgtools.org ++ ++owGbwMvMwMVYWXlhlrhb9GXG03JJDKF/MtxDMjKLFYAoUaEktbhEITe1uDgxPVWP ++q5NhKjMrWAVcC9evD8z/bF/uWNjqtk/X3y5/38XGRQHm/57rrDRYuGnTw597Xqka ++uM3137/hH3Os+Jf2dc0fXOITKwJvXJvecPVs0ta+Vg7ZO1MLn8w58Xx+6L58mbka ++DGHyU9yTueZE8D+QF/Tz28Y78dqtF56R1VPn9Xw4uJqrWYdd7b3vIZ1V6R4Nh05d ++iT57d/OhWwA= ++=hG7R ++-----END PGP MESSAGE----- ++` diff --git a/vendor/github.com/keybase/go-crypto/openpgp/write.go b/vendor/github.com/keybase/go-crypto/openpgp/write.go new file mode 100644 index 000000000..89ef132b5 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/write.go @@ -0,0 +1,506 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package openpgp + +import ( + "crypto" + "hash" + "io" + "strconv" + "time" + + "github.com/keybase/go-crypto/openpgp/armor" + "github.com/keybase/go-crypto/openpgp/errors" + "github.com/keybase/go-crypto/openpgp/packet" + "github.com/keybase/go-crypto/openpgp/s2k" +) + +// DetachSign signs message with the private key from signer (which must +// already have been decrypted) and writes the signature to w. +// If config is nil, sensible defaults will be used. +func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { + return detachSign(w, signer, message, packet.SigTypeBinary, config) +} + +// ArmoredDetachSign signs message with the private key from signer (which +// must already have been decrypted) and writes an armored signature to w. +// If config is nil, sensible defaults will be used. +func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) { + return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config) +} + +// DetachSignText signs message (after canonicalising the line endings) with +// the private key from signer (which must already have been decrypted) and +// writes the signature to w. +// If config is nil, sensible defaults will be used. +func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { + return detachSign(w, signer, message, packet.SigTypeText, config) +} + +// ArmoredDetachSignText signs message (after canonicalising the line endings) +// with the private key from signer (which must already have been decrypted) +// and writes an armored signature to w. +// If config is nil, sensible defaults will be used. +func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error { + return armoredDetachSign(w, signer, message, packet.SigTypeText, config) +} + +func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { + out, err := armor.Encode(w, SignatureType, nil) + if err != nil { + return + } + err = detachSign(out, signer, message, sigType, config) + if err != nil { + return + } + return out.Close() +} + +// SignWithSigner signs the message of type sigType with s and writes the +// signature to w. +// If config is nil, sensible defaults will be used. +func SignWithSigner(s packet.Signer, w io.Writer, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { + keyId := s.KeyId() + sig := new(packet.Signature) + sig.SigType = sigType + sig.PubKeyAlgo = s.PublicKeyAlgo() + sig.Hash = config.Hash() + sig.CreationTime = config.Now() + sig.IssuerKeyId = &keyId + + s.Reset() + + wrapped := s.(hash.Hash) + + if sigType == packet.SigTypeText { + wrapped = NewCanonicalTextHash(s) + } + + io.Copy(wrapped, message) + + err = sig.Sign(s, nil, config) + if err != nil { + return + } + + err = sig.Serialize(w) + + return +} + +func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) { + signerSubkey, ok := signer.signingKey(config.Now()) + if !ok { + err = errors.InvalidArgumentError("no valid signing keys") + return + } + if signerSubkey.PrivateKey == nil { + return errors.InvalidArgumentError("signing key doesn't have a private key") + } + if signerSubkey.PrivateKey.Encrypted { + return errors.InvalidArgumentError("signing key is encrypted") + } + + sig := new(packet.Signature) + sig.SigType = sigType + sig.PubKeyAlgo = signerSubkey.PrivateKey.PubKeyAlgo + sig.Hash = config.Hash() + sig.CreationTime = config.Now() + sig.IssuerKeyId = &signerSubkey.PrivateKey.KeyId + + h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) + if err != nil { + return + } + io.Copy(wrappedHash, message) + + err = sig.Sign(h, signerSubkey.PrivateKey, config) + if err != nil { + return + } + + return sig.Serialize(w) +} + +// FileHints contains metadata about encrypted files. This metadata is, itself, +// encrypted. +type FileHints struct { + // IsBinary can be set to hint that the contents are binary data. + IsBinary bool + // FileName hints at the name of the file that should be written. It's + // truncated to 255 bytes if longer. It may be empty to suggest that the + // file should not be written to disk. It may be equal to "_CONSOLE" to + // suggest the data should not be written to disk. + FileName string + // ModTime contains the modification time of the file, or the zero time if not applicable. + ModTime time.Time +} + +// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. +// The resulting WriteCloser must be closed after the contents of the file have +// been written. +// If config is nil, sensible defaults will be used. +func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { + if hints == nil { + hints = &FileHints{} + } + + key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config) + if err != nil { + return + } + w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config) + if err != nil { + return + } + + literaldata := w + if algo := config.Compression(); algo != packet.CompressionNone { + var compConfig *packet.CompressionConfig + if config != nil { + compConfig = config.CompressionConfig + } + literaldata, err = packet.SerializeCompressed(w, algo, compConfig) + if err != nil { + return + } + } + + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds) +} + +// intersectPreferences mutates and returns a prefix of a that contains only +// the values in the intersection of a and b. The order of a is preserved. +func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) { + var j int + for _, v := range a { + for _, v2 := range b { + if v == v2 { + a[j] = v + j++ + break + } + } + } + + return a[:j] +} + +func hashToHashId(h crypto.Hash) uint8 { + v, ok := s2k.HashToHashId(h) + if !ok { + panic("tried to convert unknown hash") + } + return v +} + +// Encrypt encrypts a message to a number of recipients and, optionally, signs +// it. hints contains optional information, that is also encrypted, that aids +// the recipients in processing the message. The resulting WriteCloser must +// be closed after the contents of the file have been written. +// If config is nil, sensible defaults will be used. +func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { + var signer *packet.PrivateKey + if signed != nil { + signKey, ok := signed.signingKey(config.Now()) + if !ok { + return nil, errors.InvalidArgumentError("no valid signing keys") + } + signer = signKey.PrivateKey + if signer == nil { + return nil, errors.InvalidArgumentError("no private key in signing key") + } + if signer.Encrypted { + return nil, errors.InvalidArgumentError("signing key must be decrypted") + } + } + + // These are the possible ciphers that we'll use for the message. + candidateCiphers := []uint8{ + uint8(packet.CipherAES128), + uint8(packet.CipherAES256), + uint8(packet.CipherCAST5), + } + // These are the possible hash functions that we'll use for the signature. + candidateHashes := []uint8{ + hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA1), + hashToHashId(crypto.RIPEMD160), + } + + // If no preferences were specified, assume something safe and reasonable. + defaultCiphers := []uint8{ + uint8(packet.CipherAES128), + uint8(packet.CipherAES192), + uint8(packet.CipherAES256), + uint8(packet.CipherCAST5), + } + + defaultHashes := []uint8{ + hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.RIPEMD160), + } + + encryptKeys := make([]Key, len(to)) + for i := range to { + var ok bool + encryptKeys[i], ok = to[i].encryptionKey(config.Now()) + if !ok { + return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys") + } + + sig := to[i].primaryIdentity().SelfSignature + + preferredSymmetric := sig.PreferredSymmetric + if len(preferredSymmetric) == 0 { + preferredSymmetric = defaultCiphers + } + preferredHashes := sig.PreferredHash + if len(preferredHashes) == 0 { + preferredHashes = defaultHashes + } + candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) + candidateHashes = intersectPreferences(candidateHashes, preferredHashes) + } + + if len(candidateCiphers) == 0 { + return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common ciphers") + } + if len(candidateHashes) == 0 { + return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common hashes") + } + + cipher := packet.CipherFunction(candidateCiphers[0]) + // If the cipher specifed by config is a candidate, we'll use that. + configuredCipher := config.Cipher() + for _, c := range candidateCiphers { + cipherFunc := packet.CipherFunction(c) + if cipherFunc == configuredCipher { + cipher = cipherFunc + break + } + } + + var hash crypto.Hash + for _, hashId := range candidateHashes { + if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { + hash = h + break + } + } + + // If the hash specified by config is a candidate, we'll use that. + if configuredHash := config.Hash(); configuredHash.Available() { + for _, hashId := range candidateHashes { + if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { + hash = h + break + } + } + } + + if hash == 0 { + hashId := candidateHashes[0] + name, ok := s2k.HashIdToString(hashId) + if !ok { + name = "#" + strconv.Itoa(int(hashId)) + } + return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") + } + + symKey := make([]byte, cipher.KeySize()) + if _, err := io.ReadFull(config.Random(), symKey); err != nil { + return nil, err + } + + for _, key := range encryptKeys { + if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil { + return nil, err + } + } + + encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) + if err != nil { + return + } + + if signer != nil { + ops := &packet.OnePassSignature{ + SigType: packet.SigTypeBinary, + Hash: hash, + PubKeyAlgo: signer.PubKeyAlgo, + KeyId: signer.KeyId, + IsLast: true, + } + if err := ops.Serialize(encryptedData); err != nil { + return nil, err + } + } + + if hints == nil { + hints = &FileHints{} + } + + w := encryptedData + if signer != nil { + // If we need to write a signature packet after the literal + // data then we need to stop literalData from closing + // encryptedData. + w = noOpCloser{encryptedData} + + } + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) + if err != nil { + return nil, err + } + + if signer != nil { + return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil + } + return literalData, nil +} + +// signatureWriter hashes the contents of a message while passing it along to +// literalData. When closed, it closes literalData, writes a signature packet +// to encryptedData and then also closes encryptedData. +type signatureWriter struct { + encryptedData io.WriteCloser + literalData io.WriteCloser + hashType crypto.Hash + h hash.Hash + signer *packet.PrivateKey + config *packet.Config +} + +func (s signatureWriter) Write(data []byte) (int, error) { + s.h.Write(data) + return s.literalData.Write(data) +} + +func (s signatureWriter) Close() error { + sig := &packet.Signature{ + SigType: packet.SigTypeBinary, + PubKeyAlgo: s.signer.PubKeyAlgo, + Hash: s.hashType, + CreationTime: s.config.Now(), + IssuerKeyId: &s.signer.KeyId, + } + + if err := sig.Sign(s.h, s.signer, s.config); err != nil { + return err + } + if err := s.literalData.Close(); err != nil { + return err + } + if err := sig.Serialize(s.encryptedData); err != nil { + return err + } + return s.encryptedData.Close() +} + +// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. +// TODO: we have two of these in OpenPGP packages alone. This probably needs +// to be promoted somewhere more common. +type noOpCloser struct { + w io.Writer +} + +func (c noOpCloser) Write(data []byte) (n int, err error) { + return c.w.Write(data) +} + +func (c noOpCloser) Close() error { + return nil +} + +// AttachedSign is like openpgp.Encrypt (as in p.crypto/openpgp/write.go), but +// don't encrypt at all, just sign the literal unencrypted data. +// Unfortunately we need to duplicate some code here that's already +// in write.go +func AttachedSign(out io.WriteCloser, signed Entity, hints *FileHints, + config *packet.Config) (in io.WriteCloser, err error) { + + if hints == nil { + hints = &FileHints{} + } + + if config == nil { + config = &packet.Config{} + } + + var signer *packet.PrivateKey + + signKey, ok := signed.signingKey(config.Now()) + if !ok { + err = errors.InvalidArgumentError("no valid signing keys") + return + } + signer = signKey.PrivateKey + if signer == nil { + err = errors.InvalidArgumentError("no valid signing keys") + return + } + if signer.Encrypted { + err = errors.InvalidArgumentError("signing key must be decrypted") + return + } + + if algo := config.Compression(); algo != packet.CompressionNone { + var compConfig *packet.CompressionConfig + if config != nil { + compConfig = config.CompressionConfig + } + out, err = packet.SerializeCompressed(out, algo, compConfig) + if err != nil { + return + } + } + + hasher := crypto.SHA512 + + ops := &packet.OnePassSignature{ + SigType: packet.SigTypeBinary, + Hash: hasher, + PubKeyAlgo: signer.PubKeyAlgo, + KeyId: signer.KeyId, + IsLast: true, + } + + if err = ops.Serialize(out); err != nil { + return + } + + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + + // We don't want the literal serializer to closer the output stream + // since we're going to need to write to it when we finish up the + // signature stuff. + in, err = packet.SerializeLiteral(noOpCloser{out}, hints.IsBinary, hints.FileName, epochSeconds) + + if err != nil { + return + } + + // If we need to write a signature packet after the literal + // data then we need to stop literalData from closing + // encryptedData. + in = signatureWriter{out, in, hasher, hasher.New(), signer, config} + + return +} diff --git a/vendor/github.com/keybase/go-crypto/rsa/pkcs1v15.go b/vendor/github.com/keybase/go-crypto/rsa/pkcs1v15.go new file mode 100644 index 000000000..5c5f415c8 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/rsa/pkcs1v15.go @@ -0,0 +1,325 @@ +// 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 rsa + +import ( + "crypto" + "crypto/subtle" + "errors" + "io" + "math/big" +) + +// This file implements encryption and decryption using PKCS#1 v1.5 padding. + +// PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using +// the crypto.Decrypter interface. +type PKCS1v15DecryptOptions struct { + // SessionKeyLen is the length of the session key that is being + // decrypted. If not zero, then a padding error during decryption will + // cause a random plaintext of this length to be returned rather than + // an error. These alternatives happen in constant time. + SessionKeyLen int +} + +// EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5. +// The message must be no longer than the length of the public modulus minus 11 bytes. +// +// The rand parameter is used as a source of entropy to ensure that encrypting +// the same message twice doesn't result in the same ciphertext. +// +// WARNING: use of this function to encrypt plaintexts other than session keys +// is dangerous. Use RSA OAEP in new protocols. +func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) { + if err := checkPub(pub); err != nil { + return nil, err + } + k := (pub.N.BitLen() + 7) / 8 + if len(msg) > k-11 { + err = ErrMessageTooLong + return + } + + // EM = 0x00 || 0x02 || PS || 0x00 || M + em := make([]byte, k) + em[1] = 2 + ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):] + err = nonZeroRandomBytes(ps, rand) + if err != nil { + return + } + em[len(em)-len(msg)-1] = 0 + copy(mm, msg) + + m := new(big.Int).SetBytes(em) + c := encrypt(new(big.Int), pub, m) + + copyWithLeftPad(em, c.Bytes()) + out = em + return +} + +// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5. +// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. +// +// Note that whether this function returns an error or not discloses secret +// information. If an attacker can cause this function to run repeatedly and +// learn whether each instance returned an error then they can decrypt and +// forge signatures as if they had the private key. See +// DecryptPKCS1v15SessionKey for a way of solving this problem. +func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) { + if err := checkPub(&priv.PublicKey); err != nil { + return nil, err + } + valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext) + if err != nil { + return + } + if valid == 0 { + return nil, ErrDecryption + } + out = out[index:] + return +} + +// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5. +// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks. +// It returns an error if the ciphertext is the wrong length or if the +// ciphertext is greater than the public modulus. Otherwise, no error is +// returned. If the padding is valid, the resulting plaintext message is copied +// into key. Otherwise, key is unchanged. These alternatives occur in constant +// time. It is intended that the user of this function generate a random +// session key beforehand and continue the protocol with the resulting value. +// This will remove any possibility that an attacker can learn any information +// about the plaintext. +// See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA +// Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology +// (Crypto '98). +// +// Note that if the session key is too small then it may be possible for an +// attacker to brute-force it. If they can do that then they can learn whether +// a random value was used (because it'll be different for the same ciphertext) +// and thus whether the padding was correct. This defeats the point of this +// function. Using at least a 16-byte key will protect against this attack. +func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) { + if err := checkPub(&priv.PublicKey); err != nil { + return err + } + k := (priv.N.BitLen() + 7) / 8 + if k-(len(key)+3+8) < 0 { + return ErrDecryption + } + + valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext) + if err != nil { + return + } + + if len(em) != k { + // This should be impossible because decryptPKCS1v15 always + // returns the full slice. + return ErrDecryption + } + + valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key))) + subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):]) + return +} + +// decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if +// rand is not nil. It returns one or zero in valid that indicates whether the +// plaintext was correctly structured. In either case, the plaintext is +// returned in em so that it may be read independently of whether it was valid +// in order to maintain constant memory access patterns. If the plaintext was +// valid then index contains the index of the original message in em. +func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) { + k := (priv.N.BitLen() + 7) / 8 + if k < 11 { + err = ErrDecryption + return + } + + c := new(big.Int).SetBytes(ciphertext) + m, err := decrypt(rand, priv, c) + if err != nil { + return + } + + em = leftPad(m.Bytes(), k) + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2) + + // The remainder of the plaintext must be a string of non-zero random + // octets, followed by a 0, followed by the message. + // lookingForIndex: 1 iff we are still looking for the zero. + // index: the offset of the first zero byte. + lookingForIndex := 1 + + for i := 2; i < len(em); i++ { + equals0 := subtle.ConstantTimeByteEq(em[i], 0) + index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) + lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) + } + + // The PS padding must be at least 8 bytes long, and it starts two + // bytes into em. + validPS := subtle.ConstantTimeLessOrEq(2+8, index) + + valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) & validPS + index = subtle.ConstantTimeSelect(valid, index+1, 0) + return valid, em, index, nil +} + +// nonZeroRandomBytes fills the given slice with non-zero random octets. +func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) { + _, err = io.ReadFull(rand, s) + if err != nil { + return + } + + for i := 0; i < len(s); i++ { + for s[i] == 0 { + _, err = io.ReadFull(rand, s[i:i+1]) + if err != nil { + return + } + // In tests, the PRNG may return all zeros so we do + // this to break the loop. + s[i] ^= 0x42 + } + } + + return +} + +// These are ASN1 DER structures: +// DigestInfo ::= SEQUENCE { +// digestAlgorithm AlgorithmIdentifier, +// digest OCTET STRING +// } +// For performance, we don't use the generic ASN1 encoder. Rather, we +// precompute a prefix of the digest value that makes a valid ASN1 DER string +// with the correct contents. +var hashPrefixes = map[crypto.Hash][]byte{ + crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, + crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, + crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, + crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, + crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, + crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, + crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix. + crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, +} + +// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. +// Note that hashed must be the result of hashing the input message using the +// given hash function. If hash is zero, hashed is signed directly. This isn't +// advisable except for interoperability. +// +// If rand is not nil then RSA blinding will be used to avoid timing side-channel attacks. +// +// This function is deterministic. Thus, if the set of possible messages is +// small, an attacker may be able to build a map from messages to signatures +// and identify the signed messages. As ever, signatures provide authenticity, +// not confidentiality. +func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) { + hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) + if err != nil { + return + } + + tLen := len(prefix) + hashLen + k := (priv.N.BitLen() + 7) / 8 + if k < tLen+11 { + return nil, ErrMessageTooLong + } + + // EM = 0x00 || 0x01 || PS || 0x00 || T + em := make([]byte, k) + em[1] = 1 + for i := 2; i < k-tLen-1; i++ { + em[i] = 0xff + } + copy(em[k-tLen:k-hashLen], prefix) + copy(em[k-hashLen:k], hashed) + + m := new(big.Int).SetBytes(em) + c, err := decryptAndCheck(rand, priv, m) + if err != nil { + return + } + + copyWithLeftPad(em, c.Bytes()) + s = em + return +} + +// VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature. +// hashed is the result of hashing the input message using the given hash +// function and sig is the signature. A valid signature is indicated by +// returning a nil error. If hash is zero then hashed is used directly. This +// isn't advisable except for interoperability. +func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) { + hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) + if err != nil { + return + } + + tLen := len(prefix) + hashLen + k := (pub.N.BitLen() + 7) / 8 + if k < tLen+11 { + err = ErrVerification + return + } + + c := new(big.Int).SetBytes(sig) + m := encrypt(new(big.Int), pub, c) + em := leftPad(m.Bytes(), k) + // EM = 0x00 || 0x01 || PS || 0x00 || T + + ok := subtle.ConstantTimeByteEq(em[0], 0) + ok &= subtle.ConstantTimeByteEq(em[1], 1) + ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed) + ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix) + ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0) + + for i := 2; i < k-tLen-1; i++ { + ok &= subtle.ConstantTimeByteEq(em[i], 0xff) + } + + if ok != 1 { + return ErrVerification + } + + return nil +} + +func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) { + // Special case: crypto.Hash(0) is used to indicate that the data is + // signed directly. + if hash == 0 { + return inLen, nil, nil + } + + hashLen = hash.Size() + if inLen != hashLen { + return 0, nil, errors.New("crypto/rsa: input must be hashed message") + } + prefix, ok := hashPrefixes[hash] + if !ok { + return 0, nil, errors.New("crypto/rsa: unsupported hash function") + } + return +} + +// copyWithLeftPad copies src to the end of dest, padding with zero bytes as +// needed. +func copyWithLeftPad(dest, src []byte) { + numPaddingBytes := len(dest) - len(src) + for i := 0; i < numPaddingBytes; i++ { + dest[i] = 0 + } + copy(dest[numPaddingBytes:], src) +} diff --git a/vendor/github.com/keybase/go-crypto/rsa/pss.go b/vendor/github.com/keybase/go-crypto/rsa/pss.go new file mode 100644 index 000000000..8a94589b1 --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/rsa/pss.go @@ -0,0 +1,297 @@ +// 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 rsa + +// This file implements the PSS signature scheme [1]. +// +// [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf + +import ( + "bytes" + "crypto" + "errors" + "hash" + "io" + "math/big" +) + +func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) { + // See [1], section 9.1.1 + hLen := hash.Size() + sLen := len(salt) + emLen := (emBits + 7) / 8 + + // 1. If the length of M is greater than the input limitation for the + // hash function (2^61 - 1 octets for SHA-1), output "message too + // long" and stop. + // + // 2. Let mHash = Hash(M), an octet string of length hLen. + + if len(mHash) != hLen { + return nil, errors.New("crypto/rsa: input must be hashed message") + } + + // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. + + if emLen < hLen+sLen+2 { + return nil, errors.New("crypto/rsa: encoding error") + } + + em := make([]byte, emLen) + db := em[:emLen-sLen-hLen-2+1+sLen] + h := em[emLen-sLen-hLen-2+1+sLen : emLen-1] + + // 4. Generate a random octet string salt of length sLen; if sLen = 0, + // then salt is the empty string. + // + // 5. Let + // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; + // + // M' is an octet string of length 8 + hLen + sLen with eight + // initial zero octets. + // + // 6. Let H = Hash(M'), an octet string of length hLen. + + var prefix [8]byte + + hash.Write(prefix[:]) + hash.Write(mHash) + hash.Write(salt) + + h = hash.Sum(h[:0]) + hash.Reset() + + // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + // zero octets. The length of PS may be 0. + // + // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length + // emLen - hLen - 1. + + db[emLen-sLen-hLen-2] = 0x01 + copy(db[emLen-sLen-hLen-1:], salt) + + // 9. Let dbMask = MGF(H, emLen - hLen - 1). + // + // 10. Let maskedDB = DB \xor dbMask. + + mgf1XOR(db, hash, h) + + // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in + // maskedDB to zero. + + db[0] &= (0xFF >> uint(8*emLen-emBits)) + + // 12. Let EM = maskedDB || H || 0xbc. + em[emLen-1] = 0xBC + + // 13. Output EM. + return em, nil +} + +func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { + // 1. If the length of M is greater than the input limitation for the + // hash function (2^61 - 1 octets for SHA-1), output "inconsistent" + // and stop. + // + // 2. Let mHash = Hash(M), an octet string of length hLen. + hLen := hash.Size() + if hLen != len(mHash) { + return ErrVerification + } + + // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. + emLen := (emBits + 7) / 8 + if emLen < hLen+sLen+2 { + return ErrVerification + } + + // 4. If the rightmost octet of EM does not have hexadecimal value + // 0xbc, output "inconsistent" and stop. + if em[len(em)-1] != 0xBC { + return ErrVerification + } + + // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and + // let H be the next hLen octets. + db := em[:emLen-hLen-1] + h := em[emLen-hLen-1 : len(em)-1] + + // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in + // maskedDB are not all equal to zero, output "inconsistent" and + // stop. + if em[0]&(0xFF<> uint(8*emLen-emBits)) + + if sLen == PSSSaltLengthAuto { + FindSaltLength: + for sLen = emLen - (hLen + 2); sLen >= 0; sLen-- { + switch db[emLen-hLen-sLen-2] { + case 1: + break FindSaltLength + case 0: + continue + default: + return ErrVerification + } + } + if sLen < 0 { + return ErrVerification + } + } else { + // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero + // or if the octet at position emLen - hLen - sLen - 1 (the leftmost + // position is "position 1") does not have hexadecimal value 0x01, + // output "inconsistent" and stop. + for _, e := range db[:emLen-hLen-sLen-2] { + if e != 0x00 { + return ErrVerification + } + } + if db[emLen-hLen-sLen-2] != 0x01 { + return ErrVerification + } + } + + // 11. Let salt be the last sLen octets of DB. + salt := db[len(db)-sLen:] + + // 12. Let + // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; + // M' is an octet string of length 8 + hLen + sLen with eight + // initial zero octets. + // + // 13. Let H' = Hash(M'), an octet string of length hLen. + var prefix [8]byte + hash.Write(prefix[:]) + hash.Write(mHash) + hash.Write(salt) + + h0 := hash.Sum(nil) + + // 14. If H = H', output "consistent." Otherwise, output "inconsistent." + if !bytes.Equal(h0, h) { + return ErrVerification + } + return nil +} + +// signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt. +// Note that hashed must be the result of hashing the input message using the +// given hash function. salt is a random sequence of bytes whose length will be +// later used to verify the signature. +func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { + nBits := priv.N.BitLen() + em, err := emsaPSSEncode(hashed, nBits-1, salt, hash.New()) + if err != nil { + return + } + m := new(big.Int).SetBytes(em) + c, err := decryptAndCheck(rand, priv, m) + if err != nil { + return + } + s = make([]byte, (nBits+7)/8) + copyWithLeftPad(s, c.Bytes()) + return +} + +const ( + // PSSSaltLengthAuto causes the salt in a PSS signature to be as large + // as possible when signing, and to be auto-detected when verifying. + PSSSaltLengthAuto = 0 + // PSSSaltLengthEqualsHash causes the salt length to equal the length + // of the hash used in the signature. + PSSSaltLengthEqualsHash = -1 +) + +// PSSOptions contains options for creating and verifying PSS signatures. +type PSSOptions struct { + // SaltLength controls the length of the salt used in the PSS + // signature. It can either be a number of bytes, or one of the special + // PSSSaltLength constants. + SaltLength int + + // Hash, if not zero, overrides the hash function passed to SignPSS. + // This is the only way to specify the hash function when using the + // crypto.Signer interface. + Hash crypto.Hash +} + +// HashFunc returns pssOpts.Hash so that PSSOptions implements +// crypto.SignerOpts. +func (pssOpts *PSSOptions) HashFunc() crypto.Hash { + return pssOpts.Hash +} + +func (opts *PSSOptions) saltLength() int { + if opts == nil { + return PSSSaltLengthAuto + } + return opts.SaltLength +} + +// SignPSS calculates the signature of hashed using RSASSA-PSS [1]. +// Note that hashed must be the result of hashing the input message using the +// given hash function. The opts argument may be nil, in which case sensible +// defaults are used. +func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) { + saltLength := opts.saltLength() + switch saltLength { + case PSSSaltLengthAuto: + saltLength = (priv.N.BitLen()+7)/8 - 2 - hash.Size() + case PSSSaltLengthEqualsHash: + saltLength = hash.Size() + } + + if opts != nil && opts.Hash != 0 { + hash = opts.Hash + } + + salt := make([]byte, saltLength) + if _, err = io.ReadFull(rand, salt); err != nil { + return + } + return signPSSWithSalt(rand, priv, hash, hashed, salt) +} + +// VerifyPSS verifies a PSS signature. +// hashed is the result of hashing the input message using the given hash +// function and sig is the signature. A valid signature is indicated by +// returning a nil error. The opts argument may be nil, in which case sensible +// defaults are used. +func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts *PSSOptions) error { + return verifyPSS(pub, hash, hashed, sig, opts.saltLength()) +} + +// verifyPSS verifies a PSS signature with the given salt length. +func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, saltLen int) error { + nBits := pub.N.BitLen() + if len(sig) != (nBits+7)/8 { + return ErrVerification + } + s := new(big.Int).SetBytes(sig) + m := encrypt(new(big.Int), pub, s) + emBits := nBits - 1 + emLen := (emBits + 7) / 8 + if emLen < len(m.Bytes()) { + return ErrVerification + } + em := make([]byte, emLen) + copyWithLeftPad(em, m.Bytes()) + if saltLen == PSSSaltLengthEqualsHash { + saltLen = hash.Size() + } + return emsaPSSVerify(hashed, em, emBits, saltLen, hash.New()) +} diff --git a/vendor/github.com/keybase/go-crypto/rsa/rsa.go b/vendor/github.com/keybase/go-crypto/rsa/rsa.go new file mode 100644 index 000000000..ff6b11b3e --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/rsa/rsa.go @@ -0,0 +1,646 @@ +// 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 rsa implements RSA encryption as specified in PKCS#1. +// +// RSA is a single, fundamental operation that is used in this package to +// implement either public-key encryption or public-key signatures. +// +// The original specification for encryption and signatures with RSA is PKCS#1 +// and the terms "RSA encryption" and "RSA signatures" by default refer to +// PKCS#1 version 1.5. However, that specification has flaws and new designs +// should use version two, usually called by just OAEP and PSS, where +// possible. +// +// Two sets of interfaces are included in this package. When a more abstract +// interface isn't neccessary, there are functions for encrypting/decrypting +// with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract +// over the public-key primitive, the PrivateKey struct implements the +// Decrypter and Signer interfaces from the crypto package. +package rsa + +import ( + "crypto" + "crypto/rand" + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" +) + +var bigZero = big.NewInt(0) +var bigOne = big.NewInt(1) + +// A PublicKey represents the public part of an RSA key. +type PublicKey struct { + N *big.Int // modulus + E int64 // public exponent +} + +// OAEPOptions is an interface for passing options to OAEP decryption using the +// crypto.Decrypter interface. +type OAEPOptions struct { + // Hash is the hash function that will be used when generating the mask. + Hash crypto.Hash + // Label is an arbitrary byte string that must be equal to the value + // used when encrypting. + Label []byte +} + +var ( + errPublicModulus = errors.New("crypto/rsa: missing public modulus") + errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small") + errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large") +) + +// checkPub sanity checks the public key before we use it. +// We require pub.E to fit into a 32-bit integer so that we +// do not have different behavior depending on whether +// int is 32 or 64 bits. See also +// http://www.imperialviolet.org/2012/03/16/rsae.html. +func checkPub(pub *PublicKey) error { + if pub.N == nil { + return errPublicModulus + } + if pub.E < 2 { + return errPublicExponentSmall + } + if pub.E > 1<<63-1 { + return errPublicExponentLarge + } + return nil +} + +// A PrivateKey represents an RSA key +type PrivateKey struct { + PublicKey // public part. + D *big.Int // private exponent + Primes []*big.Int // prime factors of N, has >= 2 elements. + + // Precomputed contains precomputed values that speed up private + // operations, if available. + Precomputed PrecomputedValues +} + +// Public returns the public key corresponding to priv. +func (priv *PrivateKey) Public() crypto.PublicKey { + return &priv.PublicKey +} + +// Sign signs msg with priv, reading randomness from rand. If opts is a +// *PSSOptions then the PSS algorithm will be used, otherwise PKCS#1 v1.5 will +// be used. This method is intended to support keys where the private part is +// kept in, for example, a hardware module. Common uses should use the Sign* +// functions in this package. +func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { + if pssOpts, ok := opts.(*PSSOptions); ok { + return SignPSS(rand, priv, pssOpts.Hash, msg, pssOpts) + } + + return SignPKCS1v15(rand, priv, opts.HashFunc(), msg) +} + +// Decrypt decrypts ciphertext with priv. If opts is nil or of type +// *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise +// opts must have type *OAEPOptions and OAEP decryption is done. +func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) { + if opts == nil { + return DecryptPKCS1v15(rand, priv, ciphertext) + } + + switch opts := opts.(type) { + case *OAEPOptions: + return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label) + + case *PKCS1v15DecryptOptions: + if l := opts.SessionKeyLen; l > 0 { + plaintext = make([]byte, l) + if _, err := io.ReadFull(rand, plaintext); err != nil { + return nil, err + } + if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil { + return nil, err + } + return plaintext, nil + } else { + return DecryptPKCS1v15(rand, priv, ciphertext) + } + + default: + return nil, errors.New("crypto/rsa: invalid options for Decrypt") + } +} + +type PrecomputedValues struct { + Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) + Qinv *big.Int // Q^-1 mod P + + // CRTValues is used for the 3rd and subsequent primes. Due to a + // historical accident, the CRT for the first two primes is handled + // differently in PKCS#1 and interoperability is sufficiently + // important that we mirror this. + CRTValues []CRTValue +} + +// CRTValue contains the precomputed Chinese remainder theorem values. +type CRTValue struct { + Exp *big.Int // D mod (prime-1). + Coeff *big.Int // R·Coeff ≡ 1 mod Prime. + R *big.Int // product of primes prior to this (inc p and q). +} + +// Validate performs basic sanity checks on the key. +// It returns nil if the key is valid, or else an error describing a problem. +func (priv *PrivateKey) Validate() error { + if err := checkPub(&priv.PublicKey); err != nil { + return err + } + + // Check that Πprimes == n. + modulus := new(big.Int).Set(bigOne) + for _, prime := range priv.Primes { + // Any primes ≤ 1 will cause divide-by-zero panics later. + if prime.Cmp(bigOne) <= 0 { + return errors.New("crypto/rsa: invalid prime value") + } + modulus.Mul(modulus, prime) + } + if modulus.Cmp(priv.N) != 0 { + return errors.New("crypto/rsa: invalid modulus") + } + + // Check that de ≡ 1 mod p-1, for each prime. + // This implies that e is coprime to each p-1 as e has a multiplicative + // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = + // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 + // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required. + congruence := new(big.Int) + de := new(big.Int).SetInt64(int64(priv.E)) + de.Mul(de, priv.D) + for _, prime := range priv.Primes { + pminus1 := new(big.Int).Sub(prime, bigOne) + congruence.Mod(de, pminus1) + if congruence.Cmp(bigOne) != 0 { + return errors.New("crypto/rsa: invalid exponents") + } + } + return nil +} + +// GenerateKey generates an RSA keypair of the given bit size using the +// random source random (for example, crypto/rand.Reader). +func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) { + return GenerateMultiPrimeKey(random, 2, bits) +} + +// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit +// size and the given random source, as suggested in [1]. Although the public +// keys are compatible (actually, indistinguishable) from the 2-prime case, +// the private keys are not. Thus it may not be possible to export multi-prime +// private keys in certain formats or to subsequently import them into other +// code. +// +// Table 1 in [2] suggests maximum numbers of primes for a given size. +// +// [1] US patent 4405829 (1972, expired) +// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf +func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error) { + priv = new(PrivateKey) + priv.E = 65537 + + if nprimes < 2 { + return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2") + } + + primes := make([]*big.Int, nprimes) + +NextSetOfPrimes: + for { + todo := bits + // crypto/rand should set the top two bits in each prime. + // Thus each prime has the form + // p_i = 2^bitlen(p_i) × 0.11... (in base 2). + // And the product is: + // P = 2^todo × α + // where α is the product of nprimes numbers of the form 0.11... + // + // If α < 1/2 (which can happen for nprimes > 2), we need to + // shift todo to compensate for lost bits: the mean value of 0.11... + // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2 + // will give good results. + if nprimes >= 7 { + todo += (nprimes - 2) / 5 + } + for i := 0; i < nprimes; i++ { + primes[i], err = rand.Prime(random, todo/(nprimes-i)) + if err != nil { + return nil, err + } + todo -= primes[i].BitLen() + } + + // Make sure that primes is pairwise unequal. + for i, prime := range primes { + for j := 0; j < i; j++ { + if prime.Cmp(primes[j]) == 0 { + continue NextSetOfPrimes + } + } + } + + n := new(big.Int).Set(bigOne) + totient := new(big.Int).Set(bigOne) + pminus1 := new(big.Int) + for _, prime := range primes { + n.Mul(n, prime) + pminus1.Sub(prime, bigOne) + totient.Mul(totient, pminus1) + } + if n.BitLen() != bits { + // This should never happen for nprimes == 2 because + // crypto/rand should set the top two bits in each prime. + // For nprimes > 2 we hope it does not happen often. + continue NextSetOfPrimes + } + + g := new(big.Int) + priv.D = new(big.Int) + y := new(big.Int) + e := big.NewInt(int64(priv.E)) + g.GCD(priv.D, y, e, totient) + + if g.Cmp(bigOne) == 0 { + if priv.D.Sign() < 0 { + priv.D.Add(priv.D, totient) + } + priv.Primes = primes + priv.N = n + + break + } + } + + priv.Precompute() + return +} + +// incCounter increments a four byte, big-endian counter. +func incCounter(c *[4]byte) { + if c[3]++; c[3] != 0 { + return + } + if c[2]++; c[2] != 0 { + return + } + if c[1]++; c[1] != 0 { + return + } + c[0]++ +} + +// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function +// specified in PKCS#1 v2.1. +func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { + var counter [4]byte + var digest []byte + + done := 0 + for done < len(out) { + hash.Write(seed) + hash.Write(counter[0:4]) + digest = hash.Sum(digest[:0]) + hash.Reset() + + for i := 0; i < len(digest) && done < len(out); i++ { + out[done] ^= digest[i] + done++ + } + incCounter(&counter) + } +} + +// ErrMessageTooLong is returned when attempting to encrypt a message which is +// too large for the size of the public key. +var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size") + +func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { + e := big.NewInt(int64(pub.E)) + c.Exp(m, e, pub.N) + return c +} + +// EncryptOAEP encrypts the given message with RSA-OAEP. +// +// OAEP is parameterised by a hash function that is used as a random oracle. +// Encryption and decryption of a given message must use the same hash function +// and sha256.New() is a reasonable choice. +// +// The random parameter is used as a source of entropy to ensure that +// encrypting the same message twice doesn't result in the same ciphertext. +// +// The label parameter may contain arbitrary data that will not be encrypted, +// but which gives important context to the message. For example, if a given +// public key is used to decrypt two types of messages then distinct label +// values could be used to ensure that a ciphertext for one purpose cannot be +// used for another by an attacker. If not required it can be empty. +// +// The message must be no longer than the length of the public modulus less +// twice the hash length plus 2. +func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) { + if err := checkPub(pub); err != nil { + return nil, err + } + hash.Reset() + k := (pub.N.BitLen() + 7) / 8 + if len(msg) > k-2*hash.Size()-2 { + err = ErrMessageTooLong + return + } + + hash.Write(label) + lHash := hash.Sum(nil) + hash.Reset() + + em := make([]byte, k) + seed := em[1 : 1+hash.Size()] + db := em[1+hash.Size():] + + copy(db[0:hash.Size()], lHash) + db[len(db)-len(msg)-1] = 1 + copy(db[len(db)-len(msg):], msg) + + _, err = io.ReadFull(random, seed) + if err != nil { + return + } + + mgf1XOR(db, hash, seed) + mgf1XOR(seed, hash, db) + + m := new(big.Int) + m.SetBytes(em) + c := encrypt(new(big.Int), pub, m) + out = c.Bytes() + + if len(out) < k { + // If the output is too small, we need to left-pad with zeros. + t := make([]byte, k) + copy(t[k-len(out):], out) + out = t + } + + return +} + +// ErrDecryption represents a failure to decrypt a message. +// It is deliberately vague to avoid adaptive attacks. +var ErrDecryption = errors.New("crypto/rsa: decryption error") + +// ErrVerification represents a failure to verify a signature. +// It is deliberately vague to avoid adaptive attacks. +var ErrVerification = errors.New("crypto/rsa: verification error") + +// modInverse returns ia, the inverse of a in the multiplicative group of prime +// order n. It requires that a be a member of the group (i.e. less than n). +func modInverse(a, n *big.Int) (ia *big.Int, ok bool) { + g := new(big.Int) + x := new(big.Int) + y := new(big.Int) + g.GCD(x, y, a, n) + if g.Cmp(bigOne) != 0 { + // In this case, a and n aren't coprime and we cannot calculate + // the inverse. This happens because the values of n are nearly + // prime (being the product of two primes) rather than truly + // prime. + return + } + + if x.Cmp(bigOne) < 0 { + // 0 is not the multiplicative inverse of any element so, if x + // < 1, then x is negative. + x.Add(x, n) + } + + return x, true +} + +// Precompute performs some calculations that speed up private key operations +// in the future. +func (priv *PrivateKey) Precompute() { + if priv.Precomputed.Dp != nil { + return + } + + priv.Precomputed.Dp = new(big.Int).Sub(priv.Primes[0], bigOne) + priv.Precomputed.Dp.Mod(priv.D, priv.Precomputed.Dp) + + priv.Precomputed.Dq = new(big.Int).Sub(priv.Primes[1], bigOne) + priv.Precomputed.Dq.Mod(priv.D, priv.Precomputed.Dq) + + priv.Precomputed.Qinv = new(big.Int).ModInverse(priv.Primes[1], priv.Primes[0]) + + r := new(big.Int).Mul(priv.Primes[0], priv.Primes[1]) + priv.Precomputed.CRTValues = make([]CRTValue, len(priv.Primes)-2) + for i := 2; i < len(priv.Primes); i++ { + prime := priv.Primes[i] + values := &priv.Precomputed.CRTValues[i-2] + + values.Exp = new(big.Int).Sub(prime, bigOne) + values.Exp.Mod(priv.D, values.Exp) + + values.R = new(big.Int).Set(r) + values.Coeff = new(big.Int).ModInverse(r, prime) + + r.Mul(r, prime) + } +} + +// decrypt performs an RSA decryption, resulting in a plaintext integer. If a +// random source is given, RSA blinding is used. +func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { + // TODO(agl): can we get away with reusing blinds? + if c.Cmp(priv.N) > 0 { + err = ErrDecryption + return + } + + var ir *big.Int + if random != nil { + // Blinding enabled. Blinding involves multiplying c by r^e. + // Then the decryption operation performs (m^e * r^e)^d mod n + // which equals mr mod n. The factor of r can then be removed + // by multiplying by the multiplicative inverse of r. + + var r *big.Int + + for { + r, err = rand.Int(random, priv.N) + if err != nil { + return + } + if r.Cmp(bigZero) == 0 { + r = bigOne + } + var ok bool + ir, ok = modInverse(r, priv.N) + if ok { + break + } + } + bigE := big.NewInt(int64(priv.E)) + rpowe := new(big.Int).Exp(r, bigE, priv.N) + cCopy := new(big.Int).Set(c) + cCopy.Mul(cCopy, rpowe) + cCopy.Mod(cCopy, priv.N) + c = cCopy + } + + if priv.Precomputed.Dp == nil { + m = new(big.Int).Exp(c, priv.D, priv.N) + } else { + // We have the precalculated values needed for the CRT. + m = new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0]) + m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1]) + m.Sub(m, m2) + if m.Sign() < 0 { + m.Add(m, priv.Primes[0]) + } + m.Mul(m, priv.Precomputed.Qinv) + m.Mod(m, priv.Primes[0]) + m.Mul(m, priv.Primes[1]) + m.Add(m, m2) + + for i, values := range priv.Precomputed.CRTValues { + prime := priv.Primes[2+i] + m2.Exp(c, values.Exp, prime) + m2.Sub(m2, m) + m2.Mul(m2, values.Coeff) + m2.Mod(m2, prime) + if m2.Sign() < 0 { + m2.Add(m2, prime) + } + m2.Mul(m2, values.R) + m.Add(m, m2) + } + } + + if ir != nil { + // Unblind. + m.Mul(m, ir) + m.Mod(m, priv.N) + } + + return +} + +func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) { + m, err = decrypt(random, priv, c) + if err != nil { + return nil, err + } + + // In order to defend against errors in the CRT computation, m^e is + // calculated, which should match the original ciphertext. + check := encrypt(new(big.Int), &priv.PublicKey, m) + if c.Cmp(check) != 0 { + return nil, errors.New("rsa: internal error") + } + return m, nil +} + +// DecryptOAEP decrypts ciphertext using RSA-OAEP. + +// OAEP is parameterised by a hash function that is used as a random oracle. +// Encryption and decryption of a given message must use the same hash function +// and sha256.New() is a reasonable choice. +// +// The random parameter, if not nil, is used to blind the private-key operation +// and avoid timing side-channel attacks. Blinding is purely internal to this +// function – the random data need not match that used when encrypting. +// +// The label parameter must match the value given when encrypting. See +// EncryptOAEP for details. +func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { + if err := checkPub(&priv.PublicKey); err != nil { + return nil, err + } + k := (priv.N.BitLen() + 7) / 8 + if len(ciphertext) > k || + k < hash.Size()*2+2 { + err = ErrDecryption + return + } + + c := new(big.Int).SetBytes(ciphertext) + + m, err := decrypt(random, priv, c) + if err != nil { + return + } + + hash.Write(label) + lHash := hash.Sum(nil) + hash.Reset() + + // Converting the plaintext number to bytes will strip any + // leading zeros so we may have to left pad. We do this unconditionally + // to avoid leaking timing information. (Although we still probably + // leak the number of leading zeros. It's not clear that we can do + // anything about this.) + em := leftPad(m.Bytes(), k) + + firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0) + + seed := em[1 : hash.Size()+1] + db := em[hash.Size()+1:] + + mgf1XOR(seed, hash, db) + mgf1XOR(db, hash, seed) + + lHash2 := db[0:hash.Size()] + + // We have to validate the plaintext in constant time in order to avoid + // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal + // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1 + // v2.0. In J. Kilian, editor, Advances in Cryptology. + lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2) + + // The remainder of the plaintext must be zero or more 0x00, followed + // by 0x01, followed by the message. + // lookingForIndex: 1 iff we are still looking for the 0x01 + // index: the offset of the first 0x01 byte + // invalid: 1 iff we saw a non-zero byte before the 0x01. + var lookingForIndex, index, invalid int + lookingForIndex = 1 + rest := db[hash.Size():] + + for i := 0; i < len(rest); i++ { + equals0 := subtle.ConstantTimeByteEq(rest[i], 0) + equals1 := subtle.ConstantTimeByteEq(rest[i], 1) + index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index) + lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex) + invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid) + } + + if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 { + err = ErrDecryption + return + } + + msg = rest[index+1:] + return +} + +// leftPad returns a new slice of length size. The contents of input are right +// aligned in the new slice. +func leftPad(input []byte, size int) (out []byte) { + n := len(input) + if n > size { + n = size + } + out = make([]byte, size) + copy(out[len(out)-n:], input) + return +} diff --git a/vendor/github.com/lib/pq/CONTRIBUTING.md b/vendor/github.com/lib/pq/CONTRIBUTING.md new file mode 100644 index 000000000..84c937f15 --- /dev/null +++ b/vendor/github.com/lib/pq/CONTRIBUTING.md @@ -0,0 +1,29 @@ +## Contributing to pq + +`pq` has a backlog of pull requests, but contributions are still very +much welcome. You can help with patch review, submitting bug reports, +or adding new functionality. There is no formal style guide, but +please conform to the style of existing code and general Go formatting +conventions when submitting patches. + +### Patch review + +Help review existing open pull requests by commenting on the code or +proposed functionality. + +### Bug reports + +We appreciate any bug reports, but especially ones with self-contained +(doesn't depend on code outside of pq), minimal (can't be simplified +further) test cases. It's especially helpful if you can submit a pull +request with just the failing test case (you'll probably want to +pattern it after the tests in +[conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). + +### New functionality + +There are a number of pending patches for new functionality, so +additional feature patches will take a while to merge. Still, patches +are generally reviewed based on usefulness and complexity in addition +to time-in-queue, so if you have a knockout idea, take a shot. Feel +free to open an issue discussion your proposed patch beforehand. diff --git a/vendor/github.com/lib/pq/LICENSE.md b/vendor/github.com/lib/pq/LICENSE.md new file mode 100644 index 000000000..5773904a3 --- /dev/null +++ b/vendor/github.com/lib/pq/LICENSE.md @@ -0,0 +1,8 @@ +Copyright (c) 2011-2013, 'pq' Contributors +Portions Copyright (C) 2011 Blake Mizerany + +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/lib/pq/README.md b/vendor/github.com/lib/pq/README.md new file mode 100644 index 000000000..d71f3c2c3 --- /dev/null +++ b/vendor/github.com/lib/pq/README.md @@ -0,0 +1,95 @@ +# pq - A pure Go postgres driver for Go's database/sql package + +[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://godoc.org/github.com/lib/pq) +[![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq) + +## Install + + go get github.com/lib/pq + +## Docs + +For detailed documentation and basic usage examples, please see the package +documentation at . + +## Tests + +`go test` is used for testing. See [TESTS.md](TESTS.md) for more details. + +## Features + +* SSL +* Handles bad connections for `database/sql` +* Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) +* Scan binary blobs correctly (i.e. `bytea`) +* Package for `hstore` support +* COPY FROM support +* pq.ParseURL for converting urls to connection strings for sql.Open. +* Many libpq compatible environment variables +* Unix socket support +* Notifications: `LISTEN`/`NOTIFY` +* pgpass support + +## Future / Things you can help with + +* Better COPY FROM / COPY TO (see discussion in #181) + +## Thank you (alphabetical) + +Some of these contributors are from the original library `bmizerany/pq.go` whose +code still exists in here. + +* Andy Balholm (andybalholm) +* Ben Berkert (benburkert) +* Benjamin Heatwole (bheatwole) +* Bill Mill (llimllib) +* Bjørn Madsen (aeons) +* Blake Gentry (bgentry) +* Brad Fitzpatrick (bradfitz) +* Charlie Melbye (cmelbye) +* Chris Bandy (cbandy) +* Chris Gilling (cgilling) +* Chris Walsh (cwds) +* Dan Sosedoff (sosedoff) +* Daniel Farina (fdr) +* Eric Chlebek (echlebek) +* Eric Garrido (minusnine) +* Eric Urban (hydrogen18) +* Everyone at The Go Team +* Evan Shaw (edsrzf) +* Ewan Chou (coocood) +* Fazal Majid (fazalmajid) +* Federico Romero (federomero) +* Fumin (fumin) +* Gary Burd (garyburd) +* Heroku (heroku) +* James Pozdena (jpoz) +* Jason McVetta (jmcvetta) +* Jeremy Jay (pbnjay) +* Joakim Sernbrant (serbaut) +* John Gallagher (jgallagher) +* Jonathan Rudenberg (titanous) +* Joël Stemmer (jstemmer) +* Kamil Kisiel (kisielk) +* Kelly Dunn (kellydunn) +* Keith Rarick (kr) +* Kir Shatrov (kirs) +* Lann Martin (lann) +* Maciek Sakrejda (uhoh-itsmaciek) +* Marc Brinkmann (mbr) +* Marko Tiikkaja (johto) +* Matt Newberry (MattNewberry) +* Matt Robenolt (mattrobenolt) +* Martin Olsen (martinolsen) +* Mike Lewis (mikelikespie) +* Nicolas Patry (Narsil) +* Oliver Tonnhofer (olt) +* Patrick Hayes (phayes) +* Paul Hammond (paulhammond) +* Ryan Smith (ryandotsmith) +* Samuel Stauffer (samuel) +* Timothée Peignier (cyberdelia) +* Travis Cline (tmc) +* TruongSinh Tran-Nguyen (truongsinh) +* Yaismel Miranda (ympons) +* notedit (notedit) diff --git a/vendor/github.com/lib/pq/TESTS.md b/vendor/github.com/lib/pq/TESTS.md new file mode 100644 index 000000000..f05021115 --- /dev/null +++ b/vendor/github.com/lib/pq/TESTS.md @@ -0,0 +1,33 @@ +# Tests + +## Running Tests + +`go test` is used for testing. A running PostgreSQL +server is required, with the ability to log in. The +database to connect to test with is "pqgotest," on +"localhost" but these can be overridden using [environment +variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html). + +Example: + + PGHOST=/run/postgresql go test + +## Benchmarks + +A benchmark suite can be run as part of the tests: + + go test -bench . + +## Example setup (Docker) + +Run a postgres container: + +``` +docker run --expose 5432:5432 postgres +``` + +Run tests: + +``` +PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test +``` diff --git a/vendor/github.com/lib/pq/array.go b/vendor/github.com/lib/pq/array.go new file mode 100644 index 000000000..e4933e227 --- /dev/null +++ b/vendor/github.com/lib/pq/array.go @@ -0,0 +1,756 @@ +package pq + +import ( + "bytes" + "database/sql" + "database/sql/driver" + "encoding/hex" + "fmt" + "reflect" + "strconv" + "strings" +) + +var typeByteSlice = reflect.TypeOf([]byte{}) +var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem() +var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem() + +// Array returns the optimal driver.Valuer and sql.Scanner for an array or +// slice of any dimension. +// +// For example: +// db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401})) +// +// var x []sql.NullInt64 +// db.QueryRow('SELECT ARRAY[235, 401]').Scan(pq.Array(&x)) +// +// Scanning multi-dimensional arrays is not supported. Arrays where the lower +// bound is not one (such as `[0:0]={1}') are not supported. +func Array(a interface{}) interface { + driver.Valuer + sql.Scanner +} { + switch a := a.(type) { + case []bool: + return (*BoolArray)(&a) + case []float64: + return (*Float64Array)(&a) + case []int64: + return (*Int64Array)(&a) + case []string: + return (*StringArray)(&a) + + case *[]bool: + return (*BoolArray)(a) + case *[]float64: + return (*Float64Array)(a) + case *[]int64: + return (*Int64Array)(a) + case *[]string: + return (*StringArray)(a) + } + + return GenericArray{a} +} + +// ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner +// to override the array delimiter used by GenericArray. +type ArrayDelimiter interface { + // ArrayDelimiter returns the delimiter character(s) for this element's type. + ArrayDelimiter() string +} + +// BoolArray represents a one-dimensional array of the PostgreSQL boolean type. +type BoolArray []bool + +// Scan implements the sql.Scanner interface. +func (a *BoolArray) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + return a.scanBytes(src) + case string: + return a.scanBytes([]byte(src)) + case nil: + *a = nil + return nil + } + + return fmt.Errorf("pq: cannot convert %T to BoolArray", src) +} + +func (a *BoolArray) scanBytes(src []byte) error { + elems, err := scanLinearArray(src, []byte{','}, "BoolArray") + if err != nil { + return err + } + if *a != nil && len(elems) == 0 { + *a = (*a)[:0] + } else { + b := make(BoolArray, len(elems)) + for i, v := range elems { + if len(v) != 1 { + return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) + } + switch v[0] { + case 't': + b[i] = true + case 'f': + b[i] = false + default: + return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) + } + } + *a = b + } + return nil +} + +// Value implements the driver.Valuer interface. +func (a BoolArray) Value() (driver.Value, error) { + if a == nil { + return nil, nil + } + + if n := len(a); n > 0 { + // There will be exactly two curly brackets, N bytes of values, + // and N-1 bytes of delimiters. + b := make([]byte, 1+2*n) + + for i := 0; i < n; i++ { + b[2*i] = ',' + if a[i] { + b[1+2*i] = 't' + } else { + b[1+2*i] = 'f' + } + } + + b[0] = '{' + b[2*n] = '}' + + return string(b), nil + } + + return "{}", nil +} + +// ByteaArray represents a one-dimensional array of the PostgreSQL bytea type. +type ByteaArray [][]byte + +// Scan implements the sql.Scanner interface. +func (a *ByteaArray) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + return a.scanBytes(src) + case string: + return a.scanBytes([]byte(src)) + case nil: + *a = nil + return nil + } + + return fmt.Errorf("pq: cannot convert %T to ByteaArray", src) +} + +func (a *ByteaArray) scanBytes(src []byte) error { + elems, err := scanLinearArray(src, []byte{','}, "ByteaArray") + if err != nil { + return err + } + if *a != nil && len(elems) == 0 { + *a = (*a)[:0] + } else { + b := make(ByteaArray, len(elems)) + for i, v := range elems { + b[i], err = parseBytea(v) + if err != nil { + return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error()) + } + } + *a = b + } + return nil +} + +// Value implements the driver.Valuer interface. It uses the "hex" format which +// is only supported on PostgreSQL 9.0 or newer. +func (a ByteaArray) Value() (driver.Value, error) { + if a == nil { + return nil, nil + } + + if n := len(a); n > 0 { + // There will be at least two curly brackets, 2*N bytes of quotes, + // 3*N bytes of hex formatting, and N-1 bytes of delimiters. + size := 1 + 6*n + for _, x := range a { + size += hex.EncodedLen(len(x)) + } + + b := make([]byte, size) + + for i, s := 0, b; i < n; i++ { + o := copy(s, `,"\\x`) + o += hex.Encode(s[o:], a[i]) + s[o] = '"' + s = s[o+1:] + } + + b[0] = '{' + b[size-1] = '}' + + return string(b), nil + } + + return "{}", nil +} + +// Float64Array represents a one-dimensional array of the PostgreSQL double +// precision type. +type Float64Array []float64 + +// Scan implements the sql.Scanner interface. +func (a *Float64Array) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + return a.scanBytes(src) + case string: + return a.scanBytes([]byte(src)) + case nil: + *a = nil + return nil + } + + return fmt.Errorf("pq: cannot convert %T to Float64Array", src) +} + +func (a *Float64Array) scanBytes(src []byte) error { + elems, err := scanLinearArray(src, []byte{','}, "Float64Array") + if err != nil { + return err + } + if *a != nil && len(elems) == 0 { + *a = (*a)[:0] + } else { + b := make(Float64Array, len(elems)) + for i, v := range elems { + if b[i], err = strconv.ParseFloat(string(v), 64); err != nil { + return fmt.Errorf("pq: parsing array element index %d: %v", i, err) + } + } + *a = b + } + return nil +} + +// Value implements the driver.Valuer interface. +func (a Float64Array) Value() (driver.Value, error) { + if a == nil { + return nil, nil + } + + if n := len(a); n > 0 { + // There will be at least two curly brackets, N bytes of values, + // and N-1 bytes of delimiters. + b := make([]byte, 1, 1+2*n) + b[0] = '{' + + b = strconv.AppendFloat(b, a[0], 'f', -1, 64) + for i := 1; i < n; i++ { + b = append(b, ',') + b = strconv.AppendFloat(b, a[i], 'f', -1, 64) + } + + return string(append(b, '}')), nil + } + + return "{}", nil +} + +// GenericArray implements the driver.Valuer and sql.Scanner interfaces for +// an array or slice of any dimension. +type GenericArray struct{ A interface{} } + +func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) { + var assign func([]byte, reflect.Value) error + var del = "," + + // TODO calculate the assign function for other types + // TODO repeat this section on the element type of arrays or slices (multidimensional) + { + if reflect.PtrTo(rt).Implements(typeSQLScanner) { + // dest is always addressable because it is an element of a slice. + assign = func(src []byte, dest reflect.Value) (err error) { + ss := dest.Addr().Interface().(sql.Scanner) + if src == nil { + err = ss.Scan(nil) + } else { + err = ss.Scan(src) + } + return + } + goto FoundType + } + + assign = func([]byte, reflect.Value) error { + return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt) + } + } + +FoundType: + + if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok { + del = ad.ArrayDelimiter() + } + + return rt, assign, del +} + +// Scan implements the sql.Scanner interface. +func (a GenericArray) Scan(src interface{}) error { + dpv := reflect.ValueOf(a.A) + switch { + case dpv.Kind() != reflect.Ptr: + return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) + case dpv.IsNil(): + return fmt.Errorf("pq: destination %T is nil", a.A) + } + + dv := dpv.Elem() + switch dv.Kind() { + case reflect.Slice: + case reflect.Array: + default: + return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) + } + + switch src := src.(type) { + case []byte: + return a.scanBytes(src, dv) + case string: + return a.scanBytes([]byte(src), dv) + case nil: + if dv.Kind() == reflect.Slice { + dv.Set(reflect.Zero(dv.Type())) + return nil + } + } + + return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type()) +} + +func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error { + dtype, assign, del := a.evaluateDestination(dv.Type().Elem()) + dims, elems, err := parseArray(src, []byte(del)) + if err != nil { + return err + } + + // TODO allow multidimensional + + if len(dims) > 1 { + return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented", + strings.Replace(fmt.Sprint(dims), " ", "][", -1)) + } + + // Treat a zero-dimensional array like an array with a single dimension of zero. + if len(dims) == 0 { + dims = append(dims, 0) + } + + for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() { + switch rt.Kind() { + case reflect.Slice: + case reflect.Array: + if rt.Len() != dims[i] { + return fmt.Errorf("pq: cannot convert ARRAY%s to %s", + strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type()) + } + default: + // TODO handle multidimensional + } + } + + values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems)) + for i, e := range elems { + if err := assign(e, values.Index(i)); err != nil { + return fmt.Errorf("pq: parsing array element index %d: %v", i, err) + } + } + + // TODO handle multidimensional + + switch dv.Kind() { + case reflect.Slice: + dv.Set(values.Slice(0, dims[0])) + case reflect.Array: + for i := 0; i < dims[0]; i++ { + dv.Index(i).Set(values.Index(i)) + } + } + + return nil +} + +// Value implements the driver.Valuer interface. +func (a GenericArray) Value() (driver.Value, error) { + if a.A == nil { + return nil, nil + } + + rv := reflect.ValueOf(a.A) + + switch rv.Kind() { + case reflect.Slice: + if rv.IsNil() { + return nil, nil + } + case reflect.Array: + default: + return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A) + } + + if n := rv.Len(); n > 0 { + // There will be at least two curly brackets, N bytes of values, + // and N-1 bytes of delimiters. + b := make([]byte, 0, 1+2*n) + + b, _, err := appendArray(b, rv, n) + return string(b), err + } + + return "{}", nil +} + +// Int64Array represents a one-dimensional array of the PostgreSQL integer types. +type Int64Array []int64 + +// Scan implements the sql.Scanner interface. +func (a *Int64Array) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + return a.scanBytes(src) + case string: + return a.scanBytes([]byte(src)) + case nil: + *a = nil + return nil + } + + return fmt.Errorf("pq: cannot convert %T to Int64Array", src) +} + +func (a *Int64Array) scanBytes(src []byte) error { + elems, err := scanLinearArray(src, []byte{','}, "Int64Array") + if err != nil { + return err + } + if *a != nil && len(elems) == 0 { + *a = (*a)[:0] + } else { + b := make(Int64Array, len(elems)) + for i, v := range elems { + if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil { + return fmt.Errorf("pq: parsing array element index %d: %v", i, err) + } + } + *a = b + } + return nil +} + +// Value implements the driver.Valuer interface. +func (a Int64Array) Value() (driver.Value, error) { + if a == nil { + return nil, nil + } + + if n := len(a); n > 0 { + // There will be at least two curly brackets, N bytes of values, + // and N-1 bytes of delimiters. + b := make([]byte, 1, 1+2*n) + b[0] = '{' + + b = strconv.AppendInt(b, a[0], 10) + for i := 1; i < n; i++ { + b = append(b, ',') + b = strconv.AppendInt(b, a[i], 10) + } + + return string(append(b, '}')), nil + } + + return "{}", nil +} + +// StringArray represents a one-dimensional array of the PostgreSQL character types. +type StringArray []string + +// Scan implements the sql.Scanner interface. +func (a *StringArray) Scan(src interface{}) error { + switch src := src.(type) { + case []byte: + return a.scanBytes(src) + case string: + return a.scanBytes([]byte(src)) + case nil: + *a = nil + return nil + } + + return fmt.Errorf("pq: cannot convert %T to StringArray", src) +} + +func (a *StringArray) scanBytes(src []byte) error { + elems, err := scanLinearArray(src, []byte{','}, "StringArray") + if err != nil { + return err + } + if *a != nil && len(elems) == 0 { + *a = (*a)[:0] + } else { + b := make(StringArray, len(elems)) + for i, v := range elems { + if b[i] = string(v); v == nil { + return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i) + } + } + *a = b + } + return nil +} + +// Value implements the driver.Valuer interface. +func (a StringArray) Value() (driver.Value, error) { + if a == nil { + return nil, nil + } + + if n := len(a); n > 0 { + // There will be at least two curly brackets, 2*N bytes of quotes, + // and N-1 bytes of delimiters. + b := make([]byte, 1, 1+3*n) + b[0] = '{' + + b = appendArrayQuotedBytes(b, []byte(a[0])) + for i := 1; i < n; i++ { + b = append(b, ',') + b = appendArrayQuotedBytes(b, []byte(a[i])) + } + + return string(append(b, '}')), nil + } + + return "{}", nil +} + +// appendArray appends rv to the buffer, returning the extended buffer and +// the delimiter used between elements. +// +// It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice. +func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) { + var del string + var err error + + b = append(b, '{') + + if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil { + return b, del, err + } + + for i := 1; i < n; i++ { + b = append(b, del...) + if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil { + return b, del, err + } + } + + return append(b, '}'), del, nil +} + +// appendArrayElement appends rv to the buffer, returning the extended buffer +// and the delimiter to use before the next element. +// +// When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted +// using driver.DefaultParameterConverter and the resulting []byte or string +// is double-quoted. +// +// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO +func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) { + if k := rv.Kind(); k == reflect.Array || k == reflect.Slice { + if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) { + if n := rv.Len(); n > 0 { + return appendArray(b, rv, n) + } + + return b, "", nil + } + } + + var del = "," + var err error + var iv interface{} = rv.Interface() + + if ad, ok := iv.(ArrayDelimiter); ok { + del = ad.ArrayDelimiter() + } + + if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil { + return b, del, err + } + + switch v := iv.(type) { + case nil: + return append(b, "NULL"...), del, nil + case []byte: + return appendArrayQuotedBytes(b, v), del, nil + case string: + return appendArrayQuotedBytes(b, []byte(v)), del, nil + } + + b, err = appendValue(b, iv) + return b, del, err +} + +func appendArrayQuotedBytes(b, v []byte) []byte { + b = append(b, '"') + for { + i := bytes.IndexAny(v, `"\`) + if i < 0 { + b = append(b, v...) + break + } + if i > 0 { + b = append(b, v[:i]...) + } + b = append(b, '\\', v[i]) + v = v[i+1:] + } + return append(b, '"') +} + +func appendValue(b []byte, v driver.Value) ([]byte, error) { + return append(b, encode(nil, v, 0)...), nil +} + +// parseArray extracts the dimensions and elements of an array represented in +// text format. Only representations emitted by the backend are supported. +// Notably, whitespace around brackets and delimiters is significant, and NULL +// is case-sensitive. +// +// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO +func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) { + var depth, i int + + if len(src) < 1 || src[0] != '{' { + return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0) + } + +Open: + for i < len(src) { + switch src[i] { + case '{': + depth++ + i++ + case '}': + elems = make([][]byte, 0) + goto Close + default: + break Open + } + } + dims = make([]int, i) + +Element: + for i < len(src) { + switch src[i] { + case '{': + if depth == len(dims) { + break Element + } + depth++ + dims[depth-1] = 0 + i++ + case '"': + var elem = []byte{} + var escape bool + for i++; i < len(src); i++ { + if escape { + elem = append(elem, src[i]) + escape = false + } else { + switch src[i] { + default: + elem = append(elem, src[i]) + case '\\': + escape = true + case '"': + elems = append(elems, elem) + i++ + break Element + } + } + } + default: + for start := i; i < len(src); i++ { + if bytes.HasPrefix(src[i:], del) || src[i] == '}' { + elem := src[start:i] + if len(elem) == 0 { + return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) + } + if bytes.Equal(elem, []byte("NULL")) { + elem = nil + } + elems = append(elems, elem) + break Element + } + } + } + } + + for i < len(src) { + if bytes.HasPrefix(src[i:], del) && depth > 0 { + dims[depth-1]++ + i += len(del) + goto Element + } else if src[i] == '}' && depth > 0 { + dims[depth-1]++ + depth-- + i++ + } else { + return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) + } + } + +Close: + for i < len(src) { + if src[i] == '}' && depth > 0 { + depth-- + i++ + } else { + return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) + } + } + if depth > 0 { + err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i) + } + if err == nil { + for _, d := range dims { + if (len(elems) % d) != 0 { + err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions") + } + } + } + return +} + +func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) { + dims, elems, err := parseArray(src, del) + if err != nil { + return nil, err + } + if len(dims) > 1 { + return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ) + } + return elems, err +} diff --git a/vendor/github.com/lib/pq/buf.go b/vendor/github.com/lib/pq/buf.go new file mode 100644 index 000000000..666b0012a --- /dev/null +++ b/vendor/github.com/lib/pq/buf.go @@ -0,0 +1,91 @@ +package pq + +import ( + "bytes" + "encoding/binary" + + "github.com/lib/pq/oid" +) + +type readBuf []byte + +func (b *readBuf) int32() (n int) { + n = int(int32(binary.BigEndian.Uint32(*b))) + *b = (*b)[4:] + return +} + +func (b *readBuf) oid() (n oid.Oid) { + n = oid.Oid(binary.BigEndian.Uint32(*b)) + *b = (*b)[4:] + return +} + +// N.B: this is actually an unsigned 16-bit integer, unlike int32 +func (b *readBuf) int16() (n int) { + n = int(binary.BigEndian.Uint16(*b)) + *b = (*b)[2:] + return +} + +func (b *readBuf) string() string { + i := bytes.IndexByte(*b, 0) + if i < 0 { + errorf("invalid message format; expected string terminator") + } + s := (*b)[:i] + *b = (*b)[i+1:] + return string(s) +} + +func (b *readBuf) next(n int) (v []byte) { + v = (*b)[:n] + *b = (*b)[n:] + return +} + +func (b *readBuf) byte() byte { + return b.next(1)[0] +} + +type writeBuf struct { + buf []byte + pos int +} + +func (b *writeBuf) int32(n int) { + x := make([]byte, 4) + binary.BigEndian.PutUint32(x, uint32(n)) + b.buf = append(b.buf, x...) +} + +func (b *writeBuf) int16(n int) { + x := make([]byte, 2) + binary.BigEndian.PutUint16(x, uint16(n)) + b.buf = append(b.buf, x...) +} + +func (b *writeBuf) string(s string) { + b.buf = append(b.buf, (s + "\000")...) +} + +func (b *writeBuf) byte(c byte) { + b.buf = append(b.buf, c) +} + +func (b *writeBuf) bytes(v []byte) { + b.buf = append(b.buf, v...) +} + +func (b *writeBuf) wrap() []byte { + p := b.buf[b.pos:] + binary.BigEndian.PutUint32(p, uint32(len(p))) + return b.buf +} + +func (b *writeBuf) next(c byte) { + p := b.buf[b.pos:] + binary.BigEndian.PutUint32(p, uint32(len(p))) + b.pos = len(b.buf) + 1 + b.buf = append(b.buf, c, 0, 0, 0, 0) +} diff --git a/vendor/github.com/lib/pq/conn.go b/vendor/github.com/lib/pq/conn.go new file mode 100644 index 000000000..43c8df29f --- /dev/null +++ b/vendor/github.com/lib/pq/conn.go @@ -0,0 +1,1854 @@ +package pq + +import ( + "bufio" + "crypto/md5" + "database/sql" + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "os" + "os/user" + "path" + "path/filepath" + "strconv" + "strings" + "time" + "unicode" + + "github.com/lib/pq/oid" +) + +// Common error types +var ( + ErrNotSupported = errors.New("pq: Unsupported command") + ErrInFailedTransaction = errors.New("pq: Could not complete operation in a failed transaction") + ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server") + ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less") + ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly") + + errUnexpectedReady = errors.New("unexpected ReadyForQuery") + errNoRowsAffected = errors.New("no RowsAffected available after the empty statement") + errNoLastInsertID = errors.New("no LastInsertId available after the empty statement") +) + +// Driver is the Postgres database driver. +type Driver struct{} + +// Open opens a new connection to the database. name is a connection string. +// Most users should only use it through database/sql package from the standard +// library. +func (d *Driver) Open(name string) (driver.Conn, error) { + return Open(name) +} + +func init() { + sql.Register("postgres", &Driver{}) +} + +type parameterStatus struct { + // server version in the same format as server_version_num, or 0 if + // unavailable + serverVersion int + + // the current location based on the TimeZone value of the session, if + // available + currentLocation *time.Location +} + +type transactionStatus byte + +const ( + txnStatusIdle transactionStatus = 'I' + txnStatusIdleInTransaction transactionStatus = 'T' + txnStatusInFailedTransaction transactionStatus = 'E' +) + +func (s transactionStatus) String() string { + switch s { + case txnStatusIdle: + return "idle" + case txnStatusIdleInTransaction: + return "idle in transaction" + case txnStatusInFailedTransaction: + return "in a failed transaction" + default: + errorf("unknown transactionStatus %d", s) + } + + panic("not reached") +} + +// Dialer is the dialer interface. It can be used to obtain more control over +// how pq creates network connections. +type Dialer interface { + Dial(network, address string) (net.Conn, error) + DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) +} + +type defaultDialer struct{} + +func (d defaultDialer) Dial(ntw, addr string) (net.Conn, error) { + return net.Dial(ntw, addr) +} +func (d defaultDialer) DialTimeout(ntw, addr string, timeout time.Duration) (net.Conn, error) { + return net.DialTimeout(ntw, addr, timeout) +} + +type conn struct { + c net.Conn + buf *bufio.Reader + namei int + scratch [512]byte + txnStatus transactionStatus + txnFinish func() + + // Save connection arguments to use during CancelRequest. + dialer Dialer + opts values + + // Cancellation key data for use with CancelRequest messages. + processID int + secretKey int + + parameterStatus parameterStatus + + saveMessageType byte + saveMessageBuffer []byte + + // If true, this connection is bad and all public-facing functions should + // return ErrBadConn. + bad bool + + // If set, this connection should never use the binary format when + // receiving query results from prepared statements. Only provided for + // debugging. + disablePreparedBinaryResult bool + + // Whether to always send []byte parameters over as binary. Enables single + // round-trip mode for non-prepared Query calls. + binaryParameters bool + + // If true this connection is in the middle of a COPY + inCopy bool +} + +// Handle driver-side settings in parsed connection string. +func (cn *conn) handleDriverSettings(o values) (err error) { + boolSetting := func(key string, val *bool) error { + if value, ok := o[key]; ok { + if value == "yes" { + *val = true + } else if value == "no" { + *val = false + } else { + return fmt.Errorf("unrecognized value %q for %s", value, key) + } + } + return nil + } + + err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult) + if err != nil { + return err + } + return boolSetting("binary_parameters", &cn.binaryParameters) +} + +func (cn *conn) handlePgpass(o values) { + // if a password was supplied, do not process .pgpass + if _, ok := o["password"]; ok { + return + } + filename := os.Getenv("PGPASSFILE") + if filename == "" { + // XXX this code doesn't work on Windows where the default filename is + // XXX %APPDATA%\postgresql\pgpass.conf + // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470 + userHome := os.Getenv("HOME") + if userHome == "" { + user, err := user.Current() + if err != nil { + return + } + userHome = user.HomeDir + } + filename = filepath.Join(userHome, ".pgpass") + } + fileinfo, err := os.Stat(filename) + if err != nil { + return + } + mode := fileinfo.Mode() + if mode&(0x77) != 0 { + // XXX should warn about incorrect .pgpass permissions as psql does + return + } + file, err := os.Open(filename) + if err != nil { + return + } + defer file.Close() + scanner := bufio.NewScanner(io.Reader(file)) + hostname := o["host"] + ntw, _ := network(o) + port := o["port"] + db := o["dbname"] + username := o["user"] + // From: https://github.com/tg/pgpass/blob/master/reader.go + getFields := func(s string) []string { + fs := make([]string, 0, 5) + f := make([]rune, 0, len(s)) + + var esc bool + for _, c := range s { + switch { + case esc: + f = append(f, c) + esc = false + case c == '\\': + esc = true + case c == ':': + fs = append(fs, string(f)) + f = f[:0] + default: + f = append(f, c) + } + } + return append(fs, string(f)) + } + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + split := getFields(line) + if len(split) != 5 { + continue + } + if (split[0] == "*" || split[0] == hostname || (split[0] == "localhost" && (hostname == "" || ntw == "unix"))) && (split[1] == "*" || split[1] == port) && (split[2] == "*" || split[2] == db) && (split[3] == "*" || split[3] == username) { + o["password"] = split[4] + return + } + } +} + +func (cn *conn) writeBuf(b byte) *writeBuf { + cn.scratch[0] = b + return &writeBuf{ + buf: cn.scratch[:5], + pos: 1, + } +} + +// Open opens a new connection to the database. name is a connection string. +// Most users should only use it through database/sql package from the standard +// library. +func Open(name string) (_ driver.Conn, err error) { + return DialOpen(defaultDialer{}, name) +} + +// DialOpen opens a new connection to the database using a dialer. +func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { + // Handle any panics during connection initialization. Note that we + // specifically do *not* want to use errRecover(), as that would turn any + // connection errors into ErrBadConns, hiding the real error message from + // the user. + defer errRecoverNoErrBadConn(&err) + + o := make(values) + + // A number of defaults are applied here, in this order: + // + // * Very low precedence defaults applied in every situation + // * Environment variables + // * Explicitly passed connection information + o["host"] = "localhost" + o["port"] = "5432" + // N.B.: Extra float digits should be set to 3, but that breaks + // Postgres 8.4 and older, where the max is 2. + o["extra_float_digits"] = "2" + for k, v := range parseEnviron(os.Environ()) { + o[k] = v + } + + if strings.HasPrefix(name, "postgres://") || strings.HasPrefix(name, "postgresql://") { + name, err = ParseURL(name) + if err != nil { + return nil, err + } + } + + if err := parseOpts(name, o); err != nil { + return nil, err + } + + // Use the "fallback" application name if necessary + if fallback, ok := o["fallback_application_name"]; ok { + if _, ok := o["application_name"]; !ok { + o["application_name"] = fallback + } + } + + // We can't work with any client_encoding other than UTF-8 currently. + // However, we have historically allowed the user to set it to UTF-8 + // explicitly, and there's no reason to break such programs, so allow that. + // Note that the "options" setting could also set client_encoding, but + // parsing its value is not worth it. Instead, we always explicitly send + // client_encoding as a separate run-time parameter, which should override + // anything set in options. + if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) { + return nil, errors.New("client_encoding must be absent or 'UTF8'") + } + o["client_encoding"] = "UTF8" + // DateStyle needs a similar treatment. + if datestyle, ok := o["datestyle"]; ok { + if datestyle != "ISO, MDY" { + panic(fmt.Sprintf("setting datestyle must be absent or %v; got %v", + "ISO, MDY", datestyle)) + } + } else { + o["datestyle"] = "ISO, MDY" + } + + // If a user is not provided by any other means, the last + // resort is to use the current operating system provided user + // name. + if _, ok := o["user"]; !ok { + u, err := userCurrent() + if err != nil { + return nil, err + } + o["user"] = u + } + + cn := &conn{ + opts: o, + dialer: d, + } + err = cn.handleDriverSettings(o) + if err != nil { + return nil, err + } + cn.handlePgpass(o) + + cn.c, err = dial(d, o) + if err != nil { + return nil, err + } + + err = cn.ssl(o) + if err != nil { + return nil, err + } + + // cn.startup panics on error. Make sure we don't leak cn.c. + panicking := true + defer func() { + if panicking { + cn.c.Close() + } + }() + + cn.buf = bufio.NewReader(cn.c) + cn.startup(o) + + // reset the deadline, in case one was set (see dial) + if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { + err = cn.c.SetDeadline(time.Time{}) + } + panicking = false + return cn, err +} + +func dial(d Dialer, o values) (net.Conn, error) { + ntw, addr := network(o) + // SSL is not necessary or supported over UNIX domain sockets + if ntw == "unix" { + o["sslmode"] = "disable" + } + + // Zero or not specified means wait indefinitely. + if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { + seconds, err := strconv.ParseInt(timeout, 10, 0) + if err != nil { + return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err) + } + duration := time.Duration(seconds) * time.Second + // connect_timeout should apply to the entire connection establishment + // procedure, so we both use a timeout for the TCP connection + // establishment and set a deadline for doing the initial handshake. + // The deadline is then reset after startup() is done. + deadline := time.Now().Add(duration) + conn, err := d.DialTimeout(ntw, addr, duration) + if err != nil { + return nil, err + } + err = conn.SetDeadline(deadline) + return conn, err + } + return d.Dial(ntw, addr) +} + +func network(o values) (string, string) { + host := o["host"] + + if strings.HasPrefix(host, "/") { + sockPath := path.Join(host, ".s.PGSQL."+o["port"]) + return "unix", sockPath + } + + return "tcp", net.JoinHostPort(host, o["port"]) +} + +type values map[string]string + +// scanner implements a tokenizer for libpq-style option strings. +type scanner struct { + s []rune + i int +} + +// newScanner returns a new scanner initialized with the option string s. +func newScanner(s string) *scanner { + return &scanner{[]rune(s), 0} +} + +// Next returns the next rune. +// It returns 0, false if the end of the text has been reached. +func (s *scanner) Next() (rune, bool) { + if s.i >= len(s.s) { + return 0, false + } + r := s.s[s.i] + s.i++ + return r, true +} + +// SkipSpaces returns the next non-whitespace rune. +// It returns 0, false if the end of the text has been reached. +func (s *scanner) SkipSpaces() (rune, bool) { + r, ok := s.Next() + for unicode.IsSpace(r) && ok { + r, ok = s.Next() + } + return r, ok +} + +// parseOpts parses the options from name and adds them to the values. +// +// The parsing code is based on conninfo_parse from libpq's fe-connect.c +func parseOpts(name string, o values) error { + s := newScanner(name) + + for { + var ( + keyRunes, valRunes []rune + r rune + ok bool + ) + + if r, ok = s.SkipSpaces(); !ok { + break + } + + // Scan the key + for !unicode.IsSpace(r) && r != '=' { + keyRunes = append(keyRunes, r) + if r, ok = s.Next(); !ok { + break + } + } + + // Skip any whitespace if we're not at the = yet + if r != '=' { + r, ok = s.SkipSpaces() + } + + // The current character should be = + if r != '=' || !ok { + return fmt.Errorf(`missing "=" after %q in connection info string"`, string(keyRunes)) + } + + // Skip any whitespace after the = + if r, ok = s.SkipSpaces(); !ok { + // If we reach the end here, the last value is just an empty string as per libpq. + o[string(keyRunes)] = "" + break + } + + if r != '\'' { + for !unicode.IsSpace(r) { + if r == '\\' { + if r, ok = s.Next(); !ok { + return fmt.Errorf(`missing character after backslash`) + } + } + valRunes = append(valRunes, r) + + if r, ok = s.Next(); !ok { + break + } + } + } else { + quote: + for { + if r, ok = s.Next(); !ok { + return fmt.Errorf(`unterminated quoted string literal in connection string`) + } + switch r { + case '\'': + break quote + case '\\': + r, _ = s.Next() + fallthrough + default: + valRunes = append(valRunes, r) + } + } + } + + o[string(keyRunes)] = string(valRunes) + } + + return nil +} + +func (cn *conn) isInTransaction() bool { + return cn.txnStatus == txnStatusIdleInTransaction || + cn.txnStatus == txnStatusInFailedTransaction +} + +func (cn *conn) checkIsInTransaction(intxn bool) { + if cn.isInTransaction() != intxn { + cn.bad = true + errorf("unexpected transaction status %v", cn.txnStatus) + } +} + +func (cn *conn) Begin() (_ driver.Tx, err error) { + return cn.begin("") +} + +func (cn *conn) begin(mode string) (_ driver.Tx, err error) { + if cn.bad { + return nil, driver.ErrBadConn + } + defer cn.errRecover(&err) + + cn.checkIsInTransaction(false) + _, commandTag, err := cn.simpleExec("BEGIN" + mode) + if err != nil { + return nil, err + } + if commandTag != "BEGIN" { + cn.bad = true + return nil, fmt.Errorf("unexpected command tag %s", commandTag) + } + if cn.txnStatus != txnStatusIdleInTransaction { + cn.bad = true + return nil, fmt.Errorf("unexpected transaction status %v", cn.txnStatus) + } + return cn, nil +} + +func (cn *conn) closeTxn() { + if finish := cn.txnFinish; finish != nil { + finish() + } +} + +func (cn *conn) Commit() (err error) { + defer cn.closeTxn() + if cn.bad { + return driver.ErrBadConn + } + defer cn.errRecover(&err) + + cn.checkIsInTransaction(true) + // We don't want the client to think that everything is okay if it tries + // to commit a failed transaction. However, no matter what we return, + // database/sql will release this connection back into the free connection + // pool so we have to abort the current transaction here. Note that you + // would get the same behaviour if you issued a COMMIT in a failed + // transaction, so it's also the least surprising thing to do here. + if cn.txnStatus == txnStatusInFailedTransaction { + if err := cn.Rollback(); err != nil { + return err + } + return ErrInFailedTransaction + } + + _, commandTag, err := cn.simpleExec("COMMIT") + if err != nil { + if cn.isInTransaction() { + cn.bad = true + } + return err + } + if commandTag != "COMMIT" { + cn.bad = true + return fmt.Errorf("unexpected command tag %s", commandTag) + } + cn.checkIsInTransaction(false) + return nil +} + +func (cn *conn) Rollback() (err error) { + defer cn.closeTxn() + if cn.bad { + return driver.ErrBadConn + } + defer cn.errRecover(&err) + + cn.checkIsInTransaction(true) + _, commandTag, err := cn.simpleExec("ROLLBACK") + if err != nil { + if cn.isInTransaction() { + cn.bad = true + } + return err + } + if commandTag != "ROLLBACK" { + return fmt.Errorf("unexpected command tag %s", commandTag) + } + cn.checkIsInTransaction(false) + return nil +} + +func (cn *conn) gname() string { + cn.namei++ + return strconv.FormatInt(int64(cn.namei), 10) +} + +func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err error) { + b := cn.writeBuf('Q') + b.string(q) + cn.send(b) + + for { + t, r := cn.recv1() + switch t { + case 'C': + res, commandTag = cn.parseComplete(r.string()) + case 'Z': + cn.processReadyForQuery(r) + if res == nil && err == nil { + err = errUnexpectedReady + } + // done + return + case 'E': + err = parseError(r) + case 'I': + res = emptyRows + case 'T', 'D': + // ignore any results + default: + cn.bad = true + errorf("unknown response for simple query: %q", t) + } + } +} + +func (cn *conn) simpleQuery(q string) (res *rows, err error) { + defer cn.errRecover(&err) + + b := cn.writeBuf('Q') + b.string(q) + cn.send(b) + + for { + t, r := cn.recv1() + switch t { + case 'C', 'I': + // We allow queries which don't return any results through Query as + // well as Exec. We still have to give database/sql a rows object + // the user can close, though, to avoid connections from being + // leaked. A "rows" with done=true works fine for that purpose. + if err != nil { + cn.bad = true + errorf("unexpected message %q in simple query execution", t) + } + if res == nil { + res = &rows{ + cn: cn, + } + } + // Set the result and tag to the last command complete if there wasn't a + // query already run. Although queries usually return from here and cede + // control to Next, a query with zero results does not. + if t == 'C' && res.colNames == nil { + res.result, res.tag = cn.parseComplete(r.string()) + } + res.done = true + case 'Z': + cn.processReadyForQuery(r) + // done + return + case 'E': + res = nil + err = parseError(r) + case 'D': + if res == nil { + cn.bad = true + errorf("unexpected DataRow in simple query execution") + } + // the query didn't fail; kick off to Next + cn.saveMessage(t, r) + return + case 'T': + // res might be non-nil here if we received a previous + // CommandComplete, but that's fine; just overwrite it + res = &rows{cn: cn} + res.colNames, res.colFmts, res.colTyps = parsePortalRowDescribe(r) + + // To work around a bug in QueryRow in Go 1.2 and earlier, wait + // until the first DataRow has been received. + default: + cn.bad = true + errorf("unknown response for simple query: %q", t) + } + } +} + +type noRows struct{} + +var emptyRows noRows + +var _ driver.Result = noRows{} + +func (noRows) LastInsertId() (int64, error) { + return 0, errNoLastInsertID +} + +func (noRows) RowsAffected() (int64, error) { + return 0, errNoRowsAffected +} + +// Decides which column formats to use for a prepared statement. The input is +// an array of type oids, one element per result column. +func decideColumnFormats(colTyps []fieldDesc, forceText bool) (colFmts []format, colFmtData []byte) { + if len(colTyps) == 0 { + return nil, colFmtDataAllText + } + + colFmts = make([]format, len(colTyps)) + if forceText { + return colFmts, colFmtDataAllText + } + + allBinary := true + allText := true + for i, t := range colTyps { + switch t.OID { + // This is the list of types to use binary mode for when receiving them + // through a prepared statement. If a type appears in this list, it + // must also be implemented in binaryDecode in encode.go. + case oid.T_bytea: + fallthrough + case oid.T_int8: + fallthrough + case oid.T_int4: + fallthrough + case oid.T_int2: + fallthrough + case oid.T_uuid: + colFmts[i] = formatBinary + allText = false + + default: + allBinary = false + } + } + + if allBinary { + return colFmts, colFmtDataAllBinary + } else if allText { + return colFmts, colFmtDataAllText + } else { + colFmtData = make([]byte, 2+len(colFmts)*2) + binary.BigEndian.PutUint16(colFmtData, uint16(len(colFmts))) + for i, v := range colFmts { + binary.BigEndian.PutUint16(colFmtData[2+i*2:], uint16(v)) + } + return colFmts, colFmtData + } +} + +func (cn *conn) prepareTo(q, stmtName string) *stmt { + st := &stmt{cn: cn, name: stmtName} + + b := cn.writeBuf('P') + b.string(st.name) + b.string(q) + b.int16(0) + + b.next('D') + b.byte('S') + b.string(st.name) + + b.next('S') + cn.send(b) + + cn.readParseResponse() + st.paramTyps, st.colNames, st.colTyps = cn.readStatementDescribeResponse() + st.colFmts, st.colFmtData = decideColumnFormats(st.colTyps, cn.disablePreparedBinaryResult) + cn.readReadyForQuery() + return st +} + +func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) { + if cn.bad { + return nil, driver.ErrBadConn + } + defer cn.errRecover(&err) + + if len(q) >= 4 && strings.EqualFold(q[:4], "COPY") { + s, err := cn.prepareCopyIn(q) + if err == nil { + cn.inCopy = true + } + return s, err + } + return cn.prepareTo(q, cn.gname()), nil +} + +func (cn *conn) Close() (err error) { + // Skip cn.bad return here because we always want to close a connection. + defer cn.errRecover(&err) + + // Ensure that cn.c.Close is always run. Since error handling is done with + // panics and cn.errRecover, the Close must be in a defer. + defer func() { + cerr := cn.c.Close() + if err == nil { + err = cerr + } + }() + + // Don't go through send(); ListenerConn relies on us not scribbling on the + // scratch buffer of this connection. + return cn.sendSimpleMessage('X') +} + +// Implement the "Queryer" interface +func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) { + return cn.query(query, args) +} + +func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) { + if cn.bad { + return nil, driver.ErrBadConn + } + if cn.inCopy { + return nil, errCopyInProgress + } + defer cn.errRecover(&err) + + // Check to see if we can use the "simpleQuery" interface, which is + // *much* faster than going through prepare/exec + if len(args) == 0 { + return cn.simpleQuery(query) + } + + if cn.binaryParameters { + cn.sendBinaryModeQuery(query, args) + + cn.readParseResponse() + cn.readBindResponse() + rows := &rows{cn: cn} + rows.colNames, rows.colFmts, rows.colTyps = cn.readPortalDescribeResponse() + cn.postExecuteWorkaround() + return rows, nil + } + st := cn.prepareTo(query, "") + st.exec(args) + return &rows{ + cn: cn, + colNames: st.colNames, + colTyps: st.colTyps, + colFmts: st.colFmts, + }, nil +} + +// Implement the optional "Execer" interface for one-shot queries +func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) { + if cn.bad { + return nil, driver.ErrBadConn + } + defer cn.errRecover(&err) + + // Check to see if we can use the "simpleExec" interface, which is + // *much* faster than going through prepare/exec + if len(args) == 0 { + // ignore commandTag, our caller doesn't care + r, _, err := cn.simpleExec(query) + return r, err + } + + if cn.binaryParameters { + cn.sendBinaryModeQuery(query, args) + + cn.readParseResponse() + cn.readBindResponse() + cn.readPortalDescribeResponse() + cn.postExecuteWorkaround() + res, _, err = cn.readExecuteResponse("Execute") + return res, err + } + // Use the unnamed statement to defer planning until bind + // time, or else value-based selectivity estimates cannot be + // used. + st := cn.prepareTo(query, "") + r, err := st.Exec(args) + if err != nil { + panic(err) + } + return r, err +} + +func (cn *conn) send(m *writeBuf) { + _, err := cn.c.Write(m.wrap()) + if err != nil { + panic(err) + } +} + +func (cn *conn) sendStartupPacket(m *writeBuf) error { + _, err := cn.c.Write((m.wrap())[1:]) + return err +} + +// Send a message of type typ to the server on the other end of cn. The +// message should have no payload. This method does not use the scratch +// buffer. +func (cn *conn) sendSimpleMessage(typ byte) (err error) { + _, err = cn.c.Write([]byte{typ, '\x00', '\x00', '\x00', '\x04'}) + return err +} + +// saveMessage memorizes a message and its buffer in the conn struct. +// recvMessage will then return these values on the next call to it. This +// method is useful in cases where you have to see what the next message is +// going to be (e.g. to see whether it's an error or not) but you can't handle +// the message yourself. +func (cn *conn) saveMessage(typ byte, buf *readBuf) { + if cn.saveMessageType != 0 { + cn.bad = true + errorf("unexpected saveMessageType %d", cn.saveMessageType) + } + cn.saveMessageType = typ + cn.saveMessageBuffer = *buf +} + +// recvMessage receives any message from the backend, or returns an error if +// a problem occurred while reading the message. +func (cn *conn) recvMessage(r *readBuf) (byte, error) { + // workaround for a QueryRow bug, see exec + if cn.saveMessageType != 0 { + t := cn.saveMessageType + *r = cn.saveMessageBuffer + cn.saveMessageType = 0 + cn.saveMessageBuffer = nil + return t, nil + } + + x := cn.scratch[:5] + _, err := io.ReadFull(cn.buf, x) + if err != nil { + return 0, err + } + + // read the type and length of the message that follows + t := x[0] + n := int(binary.BigEndian.Uint32(x[1:])) - 4 + var y []byte + if n <= len(cn.scratch) { + y = cn.scratch[:n] + } else { + y = make([]byte, n) + } + _, err = io.ReadFull(cn.buf, y) + if err != nil { + return 0, err + } + *r = y + return t, nil +} + +// recv receives a message from the backend, but if an error happened while +// reading the message or the received message was an ErrorResponse, it panics. +// NoticeResponses are ignored. This function should generally be used only +// during the startup sequence. +func (cn *conn) recv() (t byte, r *readBuf) { + for { + var err error + r = &readBuf{} + t, err = cn.recvMessage(r) + if err != nil { + panic(err) + } + + switch t { + case 'E': + panic(parseError(r)) + case 'N': + // ignore + default: + return + } + } +} + +// recv1Buf is exactly equivalent to recv1, except it uses a buffer supplied by +// the caller to avoid an allocation. +func (cn *conn) recv1Buf(r *readBuf) byte { + for { + t, err := cn.recvMessage(r) + if err != nil { + panic(err) + } + + switch t { + case 'A', 'N': + // ignore + case 'S': + cn.processParameterStatus(r) + default: + return t + } + } +} + +// recv1 receives a message from the backend, panicking if an error occurs +// while attempting to read it. All asynchronous messages are ignored, with +// the exception of ErrorResponse. +func (cn *conn) recv1() (t byte, r *readBuf) { + r = &readBuf{} + t = cn.recv1Buf(r) + return t, r +} + +func (cn *conn) ssl(o values) error { + upgrade, err := ssl(o) + if err != nil { + return err + } + + if upgrade == nil { + // Nothing to do + return nil + } + + w := cn.writeBuf(0) + w.int32(80877103) + if err = cn.sendStartupPacket(w); err != nil { + return err + } + + b := cn.scratch[:1] + _, err = io.ReadFull(cn.c, b) + if err != nil { + return err + } + + if b[0] != 'S' { + return ErrSSLNotSupported + } + + cn.c, err = upgrade(cn.c) + return err +} + +// isDriverSetting returns true iff a setting is purely for configuring the +// driver's options and should not be sent to the server in the connection +// startup packet. +func isDriverSetting(key string) bool { + switch key { + case "host", "port": + return true + case "password": + return true + case "sslmode", "sslcert", "sslkey", "sslrootcert": + return true + case "fallback_application_name": + return true + case "connect_timeout": + return true + case "disable_prepared_binary_result": + return true + case "binary_parameters": + return true + + default: + return false + } +} + +func (cn *conn) startup(o values) { + w := cn.writeBuf(0) + w.int32(196608) + // Send the backend the name of the database we want to connect to, and the + // user we want to connect as. Additionally, we send over any run-time + // parameters potentially included in the connection string. If the server + // doesn't recognize any of them, it will reply with an error. + for k, v := range o { + if isDriverSetting(k) { + // skip options which can't be run-time parameters + continue + } + // The protocol requires us to supply the database name as "database" + // instead of "dbname". + if k == "dbname" { + k = "database" + } + w.string(k) + w.string(v) + } + w.string("") + if err := cn.sendStartupPacket(w); err != nil { + panic(err) + } + + for { + t, r := cn.recv() + switch t { + case 'K': + cn.processBackendKeyData(r) + case 'S': + cn.processParameterStatus(r) + case 'R': + cn.auth(r, o) + case 'Z': + cn.processReadyForQuery(r) + return + default: + errorf("unknown response for startup: %q", t) + } + } +} + +func (cn *conn) auth(r *readBuf, o values) { + switch code := r.int32(); code { + case 0: + // OK + case 3: + w := cn.writeBuf('p') + w.string(o["password"]) + cn.send(w) + + t, r := cn.recv() + if t != 'R' { + errorf("unexpected password response: %q", t) + } + + if r.int32() != 0 { + errorf("unexpected authentication response: %q", t) + } + case 5: + s := string(r.next(4)) + w := cn.writeBuf('p') + w.string("md5" + md5s(md5s(o["password"]+o["user"])+s)) + cn.send(w) + + t, r := cn.recv() + if t != 'R' { + errorf("unexpected password response: %q", t) + } + + if r.int32() != 0 { + errorf("unexpected authentication response: %q", t) + } + default: + errorf("unknown authentication response: %d", code) + } +} + +type format int + +const formatText format = 0 +const formatBinary format = 1 + +// One result-column format code with the value 1 (i.e. all binary). +var colFmtDataAllBinary = []byte{0, 1, 0, 1} + +// No result-column format codes (i.e. all text). +var colFmtDataAllText = []byte{0, 0} + +type stmt struct { + cn *conn + name string + colNames []string + colFmts []format + colFmtData []byte + colTyps []fieldDesc + paramTyps []oid.Oid + closed bool +} + +func (st *stmt) Close() (err error) { + if st.closed { + return nil + } + if st.cn.bad { + return driver.ErrBadConn + } + defer st.cn.errRecover(&err) + + w := st.cn.writeBuf('C') + w.byte('S') + w.string(st.name) + st.cn.send(w) + + st.cn.send(st.cn.writeBuf('S')) + + t, _ := st.cn.recv1() + if t != '3' { + st.cn.bad = true + errorf("unexpected close response: %q", t) + } + st.closed = true + + t, r := st.cn.recv1() + if t != 'Z' { + st.cn.bad = true + errorf("expected ready for query, but got: %q", t) + } + st.cn.processReadyForQuery(r) + + return nil +} + +func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) { + if st.cn.bad { + return nil, driver.ErrBadConn + } + defer st.cn.errRecover(&err) + + st.exec(v) + return &rows{ + cn: st.cn, + colNames: st.colNames, + colTyps: st.colTyps, + colFmts: st.colFmts, + }, nil +} + +func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) { + if st.cn.bad { + return nil, driver.ErrBadConn + } + defer st.cn.errRecover(&err) + + st.exec(v) + res, _, err = st.cn.readExecuteResponse("simple query") + return res, err +} + +func (st *stmt) exec(v []driver.Value) { + if len(v) >= 65536 { + errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(v)) + } + if len(v) != len(st.paramTyps) { + errorf("got %d parameters but the statement requires %d", len(v), len(st.paramTyps)) + } + + cn := st.cn + w := cn.writeBuf('B') + w.byte(0) // unnamed portal + w.string(st.name) + + if cn.binaryParameters { + cn.sendBinaryParameters(w, v) + } else { + w.int16(0) + w.int16(len(v)) + for i, x := range v { + if x == nil { + w.int32(-1) + } else { + b := encode(&cn.parameterStatus, x, st.paramTyps[i]) + w.int32(len(b)) + w.bytes(b) + } + } + } + w.bytes(st.colFmtData) + + w.next('E') + w.byte(0) + w.int32(0) + + w.next('S') + cn.send(w) + + cn.readBindResponse() + cn.postExecuteWorkaround() + +} + +func (st *stmt) NumInput() int { + return len(st.paramTyps) +} + +// parseComplete parses the "command tag" from a CommandComplete message, and +// returns the number of rows affected (if applicable) and a string +// identifying only the command that was executed, e.g. "ALTER TABLE". If the +// command tag could not be parsed, parseComplete panics. +func (cn *conn) parseComplete(commandTag string) (driver.Result, string) { + commandsWithAffectedRows := []string{ + "SELECT ", + // INSERT is handled below + "UPDATE ", + "DELETE ", + "FETCH ", + "MOVE ", + "COPY ", + } + + var affectedRows *string + for _, tag := range commandsWithAffectedRows { + if strings.HasPrefix(commandTag, tag) { + t := commandTag[len(tag):] + affectedRows = &t + commandTag = tag[:len(tag)-1] + break + } + } + // INSERT also includes the oid of the inserted row in its command tag. + // Oids in user tables are deprecated, and the oid is only returned when + // exactly one row is inserted, so it's unlikely to be of value to any + // real-world application and we can ignore it. + if affectedRows == nil && strings.HasPrefix(commandTag, "INSERT ") { + parts := strings.Split(commandTag, " ") + if len(parts) != 3 { + cn.bad = true + errorf("unexpected INSERT command tag %s", commandTag) + } + affectedRows = &parts[len(parts)-1] + commandTag = "INSERT" + } + // There should be no affected rows attached to the tag, just return it + if affectedRows == nil { + return driver.RowsAffected(0), commandTag + } + n, err := strconv.ParseInt(*affectedRows, 10, 64) + if err != nil { + cn.bad = true + errorf("could not parse commandTag: %s", err) + } + return driver.RowsAffected(n), commandTag +} + +type rows struct { + cn *conn + finish func() + colNames []string + colTyps []fieldDesc + colFmts []format + done bool + rb readBuf + result driver.Result + tag string +} + +func (rs *rows) Close() error { + if finish := rs.finish; finish != nil { + defer finish() + } + // no need to look at cn.bad as Next() will + for { + err := rs.Next(nil) + switch err { + case nil: + case io.EOF: + // rs.Next can return io.EOF on both 'Z' (ready for query) and 'T' (row + // description, used with HasNextResultSet). We need to fetch messages until + // we hit a 'Z', which is done by waiting for done to be set. + if rs.done { + return nil + } + default: + return err + } + } +} + +func (rs *rows) Columns() []string { + return rs.colNames +} + +func (rs *rows) Result() driver.Result { + if rs.result == nil { + return emptyRows + } + return rs.result +} + +func (rs *rows) Tag() string { + return rs.tag +} + +func (rs *rows) Next(dest []driver.Value) (err error) { + if rs.done { + return io.EOF + } + + conn := rs.cn + if conn.bad { + return driver.ErrBadConn + } + defer conn.errRecover(&err) + + for { + t := conn.recv1Buf(&rs.rb) + switch t { + case 'E': + err = parseError(&rs.rb) + case 'C', 'I': + if t == 'C' { + rs.result, rs.tag = conn.parseComplete(rs.rb.string()) + } + continue + case 'Z': + conn.processReadyForQuery(&rs.rb) + rs.done = true + if err != nil { + return err + } + return io.EOF + case 'D': + n := rs.rb.int16() + if err != nil { + conn.bad = true + errorf("unexpected DataRow after error %s", err) + } + if n < len(dest) { + dest = dest[:n] + } + for i := range dest { + l := rs.rb.int32() + if l == -1 { + dest[i] = nil + continue + } + dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i]) + } + return + case 'T': + rs.colNames, rs.colFmts, rs.colTyps = parsePortalRowDescribe(&rs.rb) + return io.EOF + default: + errorf("unexpected message after execute: %q", t) + } + } +} + +func (rs *rows) HasNextResultSet() bool { + return !rs.done +} + +func (rs *rows) NextResultSet() error { + return nil +} + +// QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be +// used as part of an SQL statement. For example: +// +// tblname := "my_table" +// data := "my_data" +// quoted := pq.QuoteIdentifier(tblname) +// err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data) +// +// Any double quotes in name will be escaped. The quoted identifier will be +// case sensitive when used in a query. If the input string contains a zero +// byte, the result will be truncated immediately before it. +func QuoteIdentifier(name string) string { + end := strings.IndexRune(name, 0) + if end > -1 { + name = name[:end] + } + return `"` + strings.Replace(name, `"`, `""`, -1) + `"` +} + +func md5s(s string) string { + h := md5.New() + h.Write([]byte(s)) + return fmt.Sprintf("%x", h.Sum(nil)) +} + +func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.Value) { + // Do one pass over the parameters to see if we're going to send any of + // them over in binary. If we are, create a paramFormats array at the + // same time. + var paramFormats []int + for i, x := range args { + _, ok := x.([]byte) + if ok { + if paramFormats == nil { + paramFormats = make([]int, len(args)) + } + paramFormats[i] = 1 + } + } + if paramFormats == nil { + b.int16(0) + } else { + b.int16(len(paramFormats)) + for _, x := range paramFormats { + b.int16(x) + } + } + + b.int16(len(args)) + for _, x := range args { + if x == nil { + b.int32(-1) + } else { + datum := binaryEncode(&cn.parameterStatus, x) + b.int32(len(datum)) + b.bytes(datum) + } + } +} + +func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) { + if len(args) >= 65536 { + errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(args)) + } + + b := cn.writeBuf('P') + b.byte(0) // unnamed statement + b.string(query) + b.int16(0) + + b.next('B') + b.int16(0) // unnamed portal and statement + cn.sendBinaryParameters(b, args) + b.bytes(colFmtDataAllText) + + b.next('D') + b.byte('P') + b.byte(0) // unnamed portal + + b.next('E') + b.byte(0) + b.int32(0) + + b.next('S') + cn.send(b) +} + +func (cn *conn) processParameterStatus(r *readBuf) { + var err error + + param := r.string() + switch param { + case "server_version": + var major1 int + var major2 int + var minor int + _, err = fmt.Sscanf(r.string(), "%d.%d.%d", &major1, &major2, &minor) + if err == nil { + cn.parameterStatus.serverVersion = major1*10000 + major2*100 + minor + } + + case "TimeZone": + cn.parameterStatus.currentLocation, err = time.LoadLocation(r.string()) + if err != nil { + cn.parameterStatus.currentLocation = nil + } + + default: + // ignore + } +} + +func (cn *conn) processReadyForQuery(r *readBuf) { + cn.txnStatus = transactionStatus(r.byte()) +} + +func (cn *conn) readReadyForQuery() { + t, r := cn.recv1() + switch t { + case 'Z': + cn.processReadyForQuery(r) + return + default: + cn.bad = true + errorf("unexpected message %q; expected ReadyForQuery", t) + } +} + +func (cn *conn) processBackendKeyData(r *readBuf) { + cn.processID = r.int32() + cn.secretKey = r.int32() +} + +func (cn *conn) readParseResponse() { + t, r := cn.recv1() + switch t { + case '1': + return + case 'E': + err := parseError(r) + cn.readReadyForQuery() + panic(err) + default: + cn.bad = true + errorf("unexpected Parse response %q", t) + } +} + +func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []fieldDesc) { + for { + t, r := cn.recv1() + switch t { + case 't': + nparams := r.int16() + paramTyps = make([]oid.Oid, nparams) + for i := range paramTyps { + paramTyps[i] = r.oid() + } + case 'n': + return paramTyps, nil, nil + case 'T': + colNames, colTyps = parseStatementRowDescribe(r) + return paramTyps, colNames, colTyps + case 'E': + err := parseError(r) + cn.readReadyForQuery() + panic(err) + default: + cn.bad = true + errorf("unexpected Describe statement response %q", t) + } + } +} + +func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []fieldDesc) { + t, r := cn.recv1() + switch t { + case 'T': + return parsePortalRowDescribe(r) + case 'n': + return nil, nil, nil + case 'E': + err := parseError(r) + cn.readReadyForQuery() + panic(err) + default: + cn.bad = true + errorf("unexpected Describe response %q", t) + } + panic("not reached") +} + +func (cn *conn) readBindResponse() { + t, r := cn.recv1() + switch t { + case '2': + return + case 'E': + err := parseError(r) + cn.readReadyForQuery() + panic(err) + default: + cn.bad = true + errorf("unexpected Bind response %q", t) + } +} + +func (cn *conn) postExecuteWorkaround() { + // Work around a bug in sql.DB.QueryRow: in Go 1.2 and earlier it ignores + // any errors from rows.Next, which masks errors that happened during the + // execution of the query. To avoid the problem in common cases, we wait + // here for one more message from the database. If it's not an error the + // query will likely succeed (or perhaps has already, if it's a + // CommandComplete), so we push the message into the conn struct; recv1 + // will return it as the next message for rows.Next or rows.Close. + // However, if it's an error, we wait until ReadyForQuery and then return + // the error to our caller. + for { + t, r := cn.recv1() + switch t { + case 'E': + err := parseError(r) + cn.readReadyForQuery() + panic(err) + case 'C', 'D', 'I': + // the query didn't fail, but we can't process this message + cn.saveMessage(t, r) + return + default: + cn.bad = true + errorf("unexpected message during extended query execution: %q", t) + } + } +} + +// Only for Exec(), since we ignore the returned data +func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, commandTag string, err error) { + for { + t, r := cn.recv1() + switch t { + case 'C': + if err != nil { + cn.bad = true + errorf("unexpected CommandComplete after error %s", err) + } + res, commandTag = cn.parseComplete(r.string()) + case 'Z': + cn.processReadyForQuery(r) + if res == nil && err == nil { + err = errUnexpectedReady + } + return res, commandTag, err + case 'E': + err = parseError(r) + case 'T', 'D', 'I': + if err != nil { + cn.bad = true + errorf("unexpected %q after error %s", t, err) + } + if t == 'I' { + res = emptyRows + } + // ignore any results + default: + cn.bad = true + errorf("unknown %s response: %q", protocolState, t) + } + } +} + +func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) { + n := r.int16() + colNames = make([]string, n) + colTyps = make([]fieldDesc, n) + for i := range colNames { + colNames[i] = r.string() + r.next(6) + colTyps[i].OID = r.oid() + colTyps[i].Len = r.int16() + colTyps[i].Mod = r.int32() + // format code not known when describing a statement; always 0 + r.next(2) + } + return +} + +func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []fieldDesc) { + n := r.int16() + colNames = make([]string, n) + colFmts = make([]format, n) + colTyps = make([]fieldDesc, n) + for i := range colNames { + colNames[i] = r.string() + r.next(6) + colTyps[i].OID = r.oid() + colTyps[i].Len = r.int16() + colTyps[i].Mod = r.int32() + colFmts[i] = format(r.int16()) + } + return +} + +// parseEnviron tries to mimic some of libpq's environment handling +// +// To ease testing, it does not directly reference os.Environ, but is +// designed to accept its output. +// +// Environment-set connection information is intended to have a higher +// precedence than a library default but lower than any explicitly +// passed information (such as in the URL or connection string). +func parseEnviron(env []string) (out map[string]string) { + out = make(map[string]string) + + for _, v := range env { + parts := strings.SplitN(v, "=", 2) + + accrue := func(keyname string) { + out[keyname] = parts[1] + } + unsupported := func() { + panic(fmt.Sprintf("setting %v not supported", parts[0])) + } + + // The order of these is the same as is seen in the + // PostgreSQL 9.1 manual. Unsupported but well-defined + // keys cause a panic; these should be unset prior to + // execution. Options which pq expects to be set to a + // certain value are allowed, but must be set to that + // value if present (they can, of course, be absent). + switch parts[0] { + case "PGHOST": + accrue("host") + case "PGHOSTADDR": + unsupported() + case "PGPORT": + accrue("port") + case "PGDATABASE": + accrue("dbname") + case "PGUSER": + accrue("user") + case "PGPASSWORD": + accrue("password") + case "PGSERVICE", "PGSERVICEFILE", "PGREALM": + unsupported() + case "PGOPTIONS": + accrue("options") + case "PGAPPNAME": + accrue("application_name") + case "PGSSLMODE": + accrue("sslmode") + case "PGSSLCERT": + accrue("sslcert") + case "PGSSLKEY": + accrue("sslkey") + case "PGSSLROOTCERT": + accrue("sslrootcert") + case "PGREQUIRESSL", "PGSSLCRL": + unsupported() + case "PGREQUIREPEER": + unsupported() + case "PGKRBSRVNAME", "PGGSSLIB": + unsupported() + case "PGCONNECT_TIMEOUT": + accrue("connect_timeout") + case "PGCLIENTENCODING": + accrue("client_encoding") + case "PGDATESTYLE": + accrue("datestyle") + case "PGTZ": + accrue("timezone") + case "PGGEQO": + accrue("geqo") + case "PGSYSCONFDIR", "PGLOCALEDIR": + unsupported() + } + } + + return out +} + +// isUTF8 returns whether name is a fuzzy variation of the string "UTF-8". +func isUTF8(name string) bool { + // Recognize all sorts of silly things as "UTF-8", like Postgres does + s := strings.Map(alnumLowerASCII, name) + return s == "utf8" || s == "unicode" +} + +func alnumLowerASCII(ch rune) rune { + if 'A' <= ch && ch <= 'Z' { + return ch + ('a' - 'A') + } + if 'a' <= ch && ch <= 'z' || '0' <= ch && ch <= '9' { + return ch + } + return -1 // discard +} diff --git a/vendor/github.com/lib/pq/conn_go18.go b/vendor/github.com/lib/pq/conn_go18.go new file mode 100644 index 000000000..a5254f2b4 --- /dev/null +++ b/vendor/github.com/lib/pq/conn_go18.go @@ -0,0 +1,131 @@ +// +build go1.8 + +package pq + +import ( + "context" + "database/sql" + "database/sql/driver" + "fmt" + "io" + "io/ioutil" +) + +// Implement the "QueryerContext" interface +func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + list := make([]driver.Value, len(args)) + for i, nv := range args { + list[i] = nv.Value + } + finish := cn.watchCancel(ctx) + r, err := cn.query(query, list) + if err != nil { + if finish != nil { + finish() + } + return nil, err + } + r.finish = finish + return r, nil +} + +// Implement the "ExecerContext" interface +func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + list := make([]driver.Value, len(args)) + for i, nv := range args { + list[i] = nv.Value + } + + if finish := cn.watchCancel(ctx); finish != nil { + defer finish() + } + + return cn.Exec(query, list) +} + +// Implement the "ConnBeginTx" interface +func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + var mode string + + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault: + // Don't touch mode: use the server's default + case sql.LevelReadUncommitted: + mode = " ISOLATION LEVEL READ UNCOMMITTED" + case sql.LevelReadCommitted: + mode = " ISOLATION LEVEL READ COMMITTED" + case sql.LevelRepeatableRead: + mode = " ISOLATION LEVEL REPEATABLE READ" + case sql.LevelSerializable: + mode = " ISOLATION LEVEL SERIALIZABLE" + default: + return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation) + } + + if opts.ReadOnly { + mode += " READ ONLY" + } else { + mode += " READ WRITE" + } + + tx, err := cn.begin(mode) + if err != nil { + return nil, err + } + cn.txnFinish = cn.watchCancel(ctx) + return tx, nil +} + +func (cn *conn) watchCancel(ctx context.Context) func() { + if done := ctx.Done(); done != nil { + finished := make(chan struct{}) + go func() { + select { + case <-done: + _ = cn.cancel() + finished <- struct{}{} + case <-finished: + } + }() + return func() { + select { + case <-finished: + case finished <- struct{}{}: + } + } + } + return nil +} + +func (cn *conn) cancel() error { + c, err := dial(cn.dialer, cn.opts) + if err != nil { + return err + } + defer c.Close() + + { + can := conn{ + c: c, + } + err = can.ssl(cn.opts) + if err != nil { + return err + } + + w := can.writeBuf(0) + w.int32(80877102) // cancel request code + w.int32(cn.processID) + w.int32(cn.secretKey) + + if err := can.sendStartupPacket(w); err != nil { + return err + } + } + + // Read until EOF to ensure that the server received the cancel. + { + _, err := io.Copy(ioutil.Discard, c) + return err + } +} diff --git a/vendor/github.com/lib/pq/connector.go b/vendor/github.com/lib/pq/connector.go new file mode 100644 index 000000000..9e66eb5df --- /dev/null +++ b/vendor/github.com/lib/pq/connector.go @@ -0,0 +1,43 @@ +// +build go1.10 + +package pq + +import ( + "context" + "database/sql/driver" +) + +// Connector represents a fixed configuration for the pq driver with a given +// name. Connector satisfies the database/sql/driver Connector interface and +// can be used to create any number of DB Conn's via the database/sql OpenDB +// function. +// +// See https://golang.org/pkg/database/sql/driver/#Connector. +// See https://golang.org/pkg/database/sql/#OpenDB. +type connector struct { + name string +} + +// Connect returns a connection to the database using the fixed configuration +// of this Connector. Context is not used. +func (c *connector) Connect(_ context.Context) (driver.Conn, error) { + return (&Driver{}).Open(c.name) +} + +// Driver returnst the underlying driver of this Connector. +func (c *connector) Driver() driver.Driver { + return &Driver{} +} + +var _ driver.Connector = &connector{} + +// NewConnector returns a connector for the pq driver in a fixed configuration +// with the given name. The returned connector can be used to create any number +// of equivalent Conn's. The returned connector is intended to be used with +// database/sql.OpenDB. +// +// See https://golang.org/pkg/database/sql/driver/#Connector. +// See https://golang.org/pkg/database/sql/#OpenDB. +func NewConnector(name string) (driver.Connector, error) { + return &connector{name: name}, nil +} diff --git a/vendor/github.com/lib/pq/copy.go b/vendor/github.com/lib/pq/copy.go new file mode 100644 index 000000000..345c2398f --- /dev/null +++ b/vendor/github.com/lib/pq/copy.go @@ -0,0 +1,282 @@ +package pq + +import ( + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "sync" +) + +var ( + errCopyInClosed = errors.New("pq: copyin statement has already been closed") + errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY") + errCopyToNotSupported = errors.New("pq: COPY TO is not supported") + errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction") + errCopyInProgress = errors.New("pq: COPY in progress") +) + +// CopyIn creates a COPY FROM statement which can be prepared with +// Tx.Prepare(). The target table should be visible in search_path. +func CopyIn(table string, columns ...string) string { + stmt := "COPY " + QuoteIdentifier(table) + " (" + for i, col := range columns { + if i != 0 { + stmt += ", " + } + stmt += QuoteIdentifier(col) + } + stmt += ") FROM STDIN" + return stmt +} + +// CopyInSchema creates a COPY FROM statement which can be prepared with +// Tx.Prepare(). +func CopyInSchema(schema, table string, columns ...string) string { + stmt := "COPY " + QuoteIdentifier(schema) + "." + QuoteIdentifier(table) + " (" + for i, col := range columns { + if i != 0 { + stmt += ", " + } + stmt += QuoteIdentifier(col) + } + stmt += ") FROM STDIN" + return stmt +} + +type copyin struct { + cn *conn + buffer []byte + rowData chan []byte + done chan bool + + closed bool + + sync.Mutex // guards err + err error +} + +const ciBufferSize = 64 * 1024 + +// flush buffer before the buffer is filled up and needs reallocation +const ciBufferFlushSize = 63 * 1024 + +func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) { + if !cn.isInTransaction() { + return nil, errCopyNotSupportedOutsideTxn + } + + ci := ©in{ + cn: cn, + buffer: make([]byte, 0, ciBufferSize), + rowData: make(chan []byte), + done: make(chan bool, 1), + } + // add CopyData identifier + 4 bytes for message length + ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0) + + b := cn.writeBuf('Q') + b.string(q) + cn.send(b) + +awaitCopyInResponse: + for { + t, r := cn.recv1() + switch t { + case 'G': + if r.byte() != 0 { + err = errBinaryCopyNotSupported + break awaitCopyInResponse + } + go ci.resploop() + return ci, nil + case 'H': + err = errCopyToNotSupported + break awaitCopyInResponse + case 'E': + err = parseError(r) + case 'Z': + if err == nil { + ci.setBad() + errorf("unexpected ReadyForQuery in response to COPY") + } + cn.processReadyForQuery(r) + return nil, err + default: + ci.setBad() + errorf("unknown response for copy query: %q", t) + } + } + + // something went wrong, abort COPY before we return + b = cn.writeBuf('f') + b.string(err.Error()) + cn.send(b) + + for { + t, r := cn.recv1() + switch t { + case 'c', 'C', 'E': + case 'Z': + // correctly aborted, we're done + cn.processReadyForQuery(r) + return nil, err + default: + ci.setBad() + errorf("unknown response for CopyFail: %q", t) + } + } +} + +func (ci *copyin) flush(buf []byte) { + // set message length (without message identifier) + binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1)) + + _, err := ci.cn.c.Write(buf) + if err != nil { + panic(err) + } +} + +func (ci *copyin) resploop() { + for { + var r readBuf + t, err := ci.cn.recvMessage(&r) + if err != nil { + ci.setBad() + ci.setError(err) + ci.done <- true + return + } + switch t { + case 'C': + // complete + case 'N': + // NoticeResponse + case 'Z': + ci.cn.processReadyForQuery(&r) + ci.done <- true + return + case 'E': + err := parseError(&r) + ci.setError(err) + default: + ci.setBad() + ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t)) + ci.done <- true + return + } + } +} + +func (ci *copyin) setBad() { + ci.Lock() + ci.cn.bad = true + ci.Unlock() +} + +func (ci *copyin) isBad() bool { + ci.Lock() + b := ci.cn.bad + ci.Unlock() + return b +} + +func (ci *copyin) isErrorSet() bool { + ci.Lock() + isSet := (ci.err != nil) + ci.Unlock() + return isSet +} + +// setError() sets ci.err if one has not been set already. Caller must not be +// holding ci.Mutex. +func (ci *copyin) setError(err error) { + ci.Lock() + if ci.err == nil { + ci.err = err + } + ci.Unlock() +} + +func (ci *copyin) NumInput() int { + return -1 +} + +func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { + return nil, ErrNotSupported +} + +// Exec inserts values into the COPY stream. The insert is asynchronous +// and Exec can return errors from previous Exec calls to the same +// COPY stmt. +// +// You need to call Exec(nil) to sync the COPY stream and to get any +// errors from pending data, since Stmt.Close() doesn't return errors +// to the user. +func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { + if ci.closed { + return nil, errCopyInClosed + } + + if ci.isBad() { + return nil, driver.ErrBadConn + } + defer ci.cn.errRecover(&err) + + if ci.isErrorSet() { + return nil, ci.err + } + + if len(v) == 0 { + return nil, ci.Close() + } + + numValues := len(v) + for i, value := range v { + ci.buffer = appendEncodedText(&ci.cn.parameterStatus, ci.buffer, value) + if i < numValues-1 { + ci.buffer = append(ci.buffer, '\t') + } + } + + ci.buffer = append(ci.buffer, '\n') + + if len(ci.buffer) > ciBufferFlushSize { + ci.flush(ci.buffer) + // reset buffer, keep bytes for message identifier and length + ci.buffer = ci.buffer[:5] + } + + return driver.RowsAffected(0), nil +} + +func (ci *copyin) Close() (err error) { + if ci.closed { // Don't do anything, we're already closed + return nil + } + ci.closed = true + + if ci.isBad() { + return driver.ErrBadConn + } + defer ci.cn.errRecover(&err) + + if len(ci.buffer) > 0 { + ci.flush(ci.buffer) + } + // Avoid touching the scratch buffer as resploop could be using it. + err = ci.cn.sendSimpleMessage('c') + if err != nil { + return err + } + + <-ci.done + ci.cn.inCopy = false + + if ci.isErrorSet() { + err = ci.err + return err + } + return nil +} diff --git a/vendor/github.com/lib/pq/doc.go b/vendor/github.com/lib/pq/doc.go new file mode 100644 index 000000000..a1b029713 --- /dev/null +++ b/vendor/github.com/lib/pq/doc.go @@ -0,0 +1,245 @@ +/* +Package pq is a pure Go Postgres driver for the database/sql package. + +In most cases clients will use the database/sql package instead of +using this package directly. For example: + + import ( + "database/sql" + + _ "github.com/lib/pq" + ) + + func main() { + connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full" + db, err := sql.Open("postgres", connStr) + if err != nil { + log.Fatal(err) + } + + age := 21 + rows, err := db.Query("SELECT name FROM users WHERE age = $1", age) + … + } + +You can also connect to a database using a URL. For example: + + connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full" + db, err := sql.Open("postgres", connStr) + + +Connection String Parameters + + +Similarly to libpq, when establishing a connection using pq you are expected to +supply a connection string containing zero or more parameters. +A subset of the connection parameters supported by libpq are also supported by pq. +Additionally, pq also lets you specify run-time parameters (such as search_path or work_mem) +directly in the connection string. This is different from libpq, which does not allow +run-time parameters in the connection string, instead requiring you to supply +them in the options parameter. + +For compatibility with libpq, the following special connection parameters are +supported: + + * dbname - The name of the database to connect to + * user - The user to sign in as + * password - The user's password + * host - The host to connect to. Values that start with / are for unix + domain sockets. (default is localhost) + * port - The port to bind to. (default is 5432) + * sslmode - Whether or not to use SSL (default is require, this is not + the default for libpq) + * fallback_application_name - An application_name to fall back to if one isn't provided. + * connect_timeout - Maximum wait for connection, in seconds. Zero or + not specified means wait indefinitely. + * sslcert - Cert file location. The file must contain PEM encoded data. + * sslkey - Key file location. The file must contain PEM encoded data. + * sslrootcert - The location of the root certificate file. The file + must contain PEM encoded data. + +Valid values for sslmode are: + + * disable - No SSL + * require - Always SSL (skip verification) + * verify-ca - Always SSL (verify that the certificate presented by the + server was signed by a trusted CA) + * verify-full - Always SSL (verify that the certification presented by + the server was signed by a trusted CA and the server host name + matches the one in the certificate) + +See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING +for more information about connection string parameters. + +Use single quotes for values that contain whitespace: + + "user=pqgotest password='with spaces'" + +A backslash will escape the next character in values: + + "user=space\ man password='it\'s valid'" + +Note that the connection parameter client_encoding (which sets the +text encoding for the connection) may be set but must be "UTF8", +matching with the same rules as Postgres. It is an error to provide +any other value. + +In addition to the parameters listed above, any run-time parameter that can be +set at backend start time can be set in the connection string. For more +information, see +http://www.postgresql.org/docs/current/static/runtime-config.html. + +Most environment variables as specified at http://www.postgresql.org/docs/current/static/libpq-envars.html +supported by libpq are also supported by pq. If any of the environment +variables not supported by pq are set, pq will panic during connection +establishment. Environment variables have a lower precedence than explicitly +provided connection parameters. + +The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html +is supported, but on Windows PGPASSFILE must be specified explicitly. + + +Queries + + +database/sql does not dictate any specific format for parameter +markers in query strings, and pq uses the Postgres-native ordinal markers, +as shown above. The same marker can be reused for the same parameter: + + rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1 + OR age BETWEEN $2 AND $2 + 3`, "orange", 64) + +pq does not support the LastInsertId() method of the Result type in database/sql. +To return the identifier of an INSERT (or UPDATE or DELETE), use the Postgres +RETURNING clause with a standard Query or QueryRow call: + + var userid int + err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age) + VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid) + +For more details on RETURNING, see the Postgres documentation: + + http://www.postgresql.org/docs/current/static/sql-insert.html + http://www.postgresql.org/docs/current/static/sql-update.html + http://www.postgresql.org/docs/current/static/sql-delete.html + +For additional instructions on querying see the documentation for the database/sql package. + + +Data Types + + +Parameters pass through driver.DefaultParameterConverter before they are handled +by this package. When the binary_parameters connection option is enabled, +[]byte values are sent directly to the backend as data in binary format. + +This package returns the following types for values from the PostgreSQL backend: + + - integer types smallint, integer, and bigint are returned as int64 + - floating-point types real and double precision are returned as float64 + - character types char, varchar, and text are returned as string + - temporal types date, time, timetz, timestamp, and timestamptz are + returned as time.Time + - the boolean type is returned as bool + - the bytea type is returned as []byte + +All other types are returned directly from the backend as []byte values in text format. + + +Errors + + +pq may return errors of type *pq.Error which can be interrogated for error details: + + if err, ok := err.(*pq.Error); ok { + fmt.Println("pq error:", err.Code.Name()) + } + +See the pq.Error type for details. + + +Bulk imports + +You can perform bulk imports by preparing a statement returned by pq.CopyIn (or +pq.CopyInSchema) in an explicit transaction (sql.Tx). The returned statement +handle can then be repeatedly "executed" to copy data into the target table. +After all data has been processed you should call Exec() once with no arguments +to flush all buffered data. Any call to Exec() might return an error which +should be handled appropriately, but because of the internal buffering an error +returned by Exec() might not be related to the data passed in the call that +failed. + +CopyIn uses COPY FROM internally. It is not possible to COPY outside of an +explicit transaction in pq. + +Usage example: + + txn, err := db.Begin() + if err != nil { + log.Fatal(err) + } + + stmt, err := txn.Prepare(pq.CopyIn("users", "name", "age")) + if err != nil { + log.Fatal(err) + } + + for _, user := range users { + _, err = stmt.Exec(user.Name, int64(user.Age)) + if err != nil { + log.Fatal(err) + } + } + + _, err = stmt.Exec() + if err != nil { + log.Fatal(err) + } + + err = stmt.Close() + if err != nil { + log.Fatal(err) + } + + err = txn.Commit() + if err != nil { + log.Fatal(err) + } + + +Notifications + + +PostgreSQL supports a simple publish/subscribe model over database +connections. See http://www.postgresql.org/docs/current/static/sql-notify.html +for more information about the general mechanism. + +To start listening for notifications, you first have to open a new connection +to the database by calling NewListener. This connection can not be used for +anything other than LISTEN / NOTIFY. Calling Listen will open a "notification +channel"; once a notification channel is open, a notification generated on that +channel will effect a send on the Listener.Notify channel. A notification +channel will remain open until Unlisten is called, though connection loss might +result in some notifications being lost. To solve this problem, Listener sends +a nil pointer over the Notify channel any time the connection is re-established +following a connection loss. The application can get information about the +state of the underlying connection by setting an event callback in the call to +NewListener. + +A single Listener can safely be used from concurrent goroutines, which means +that there is often no need to create more than one Listener in your +application. However, a Listener is always connected to a single database, so +you will need to create a new Listener instance for every database you want to +receive notifications in. + +The channel name in both Listen and Unlisten is case sensitive, and can contain +any characters legal in an identifier (see +http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS +for more information). Note that the channel name will be truncated to 63 +bytes by the PostgreSQL server. + +You can find a complete, working example of Listener usage at +http://godoc.org/github.com/lib/pq/example/listen. + +*/ +package pq diff --git a/vendor/github.com/lib/pq/encode.go b/vendor/github.com/lib/pq/encode.go new file mode 100644 index 000000000..3b0d365f2 --- /dev/null +++ b/vendor/github.com/lib/pq/encode.go @@ -0,0 +1,603 @@ +package pq + +import ( + "bytes" + "database/sql/driver" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "math" + "strconv" + "strings" + "sync" + "time" + + "github.com/lib/pq/oid" +) + +func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte { + switch v := x.(type) { + case []byte: + return v + default: + return encode(parameterStatus, x, oid.T_unknown) + } +} + +func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte { + switch v := x.(type) { + case int64: + return strconv.AppendInt(nil, v, 10) + case float64: + return strconv.AppendFloat(nil, v, 'f', -1, 64) + case []byte: + if pgtypOid == oid.T_bytea { + return encodeBytea(parameterStatus.serverVersion, v) + } + + return v + case string: + if pgtypOid == oid.T_bytea { + return encodeBytea(parameterStatus.serverVersion, []byte(v)) + } + + return []byte(v) + case bool: + return strconv.AppendBool(nil, v) + case time.Time: + return formatTs(v) + + default: + errorf("encode: unknown type for %T", v) + } + + panic("not reached") +} + +func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid, f format) interface{} { + switch f { + case formatBinary: + return binaryDecode(parameterStatus, s, typ) + case formatText: + return textDecode(parameterStatus, s, typ) + default: + panic("not reached") + } +} + +func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} { + switch typ { + case oid.T_bytea: + return s + case oid.T_int8: + return int64(binary.BigEndian.Uint64(s)) + case oid.T_int4: + return int64(int32(binary.BigEndian.Uint32(s))) + case oid.T_int2: + return int64(int16(binary.BigEndian.Uint16(s))) + case oid.T_uuid: + b, err := decodeUUIDBinary(s) + if err != nil { + panic(err) + } + return b + + default: + errorf("don't know how to decode binary parameter of type %d", uint32(typ)) + } + + panic("not reached") +} + +func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} { + switch typ { + case oid.T_char, oid.T_varchar, oid.T_text: + return string(s) + case oid.T_bytea: + b, err := parseBytea(s) + if err != nil { + errorf("%s", err) + } + return b + case oid.T_timestamptz: + return parseTs(parameterStatus.currentLocation, string(s)) + case oid.T_timestamp, oid.T_date: + return parseTs(nil, string(s)) + case oid.T_time: + return mustParse("15:04:05", typ, s) + case oid.T_timetz: + return mustParse("15:04:05-07", typ, s) + case oid.T_bool: + return s[0] == 't' + case oid.T_int8, oid.T_int4, oid.T_int2: + i, err := strconv.ParseInt(string(s), 10, 64) + if err != nil { + errorf("%s", err) + } + return i + case oid.T_float4, oid.T_float8: + bits := 64 + if typ == oid.T_float4 { + bits = 32 + } + f, err := strconv.ParseFloat(string(s), bits) + if err != nil { + errorf("%s", err) + } + return f + } + + return s +} + +// appendEncodedText encodes item in text format as required by COPY +// and appends to buf +func appendEncodedText(parameterStatus *parameterStatus, buf []byte, x interface{}) []byte { + switch v := x.(type) { + case int64: + return strconv.AppendInt(buf, v, 10) + case float64: + return strconv.AppendFloat(buf, v, 'f', -1, 64) + case []byte: + encodedBytea := encodeBytea(parameterStatus.serverVersion, v) + return appendEscapedText(buf, string(encodedBytea)) + case string: + return appendEscapedText(buf, v) + case bool: + return strconv.AppendBool(buf, v) + case time.Time: + return append(buf, formatTs(v)...) + case nil: + return append(buf, "\\N"...) + default: + errorf("encode: unknown type for %T", v) + } + + panic("not reached") +} + +func appendEscapedText(buf []byte, text string) []byte { + escapeNeeded := false + startPos := 0 + var c byte + + // check if we need to escape + for i := 0; i < len(text); i++ { + c = text[i] + if c == '\\' || c == '\n' || c == '\r' || c == '\t' { + escapeNeeded = true + startPos = i + break + } + } + if !escapeNeeded { + return append(buf, text...) + } + + // copy till first char to escape, iterate the rest + result := append(buf, text[:startPos]...) + for i := startPos; i < len(text); i++ { + c = text[i] + switch c { + case '\\': + result = append(result, '\\', '\\') + case '\n': + result = append(result, '\\', 'n') + case '\r': + result = append(result, '\\', 'r') + case '\t': + result = append(result, '\\', 't') + default: + result = append(result, c) + } + } + return result +} + +func mustParse(f string, typ oid.Oid, s []byte) time.Time { + str := string(s) + + // check for a 30-minute-offset timezone + if (typ == oid.T_timestamptz || typ == oid.T_timetz) && + str[len(str)-3] == ':' { + f += ":00" + } + t, err := time.Parse(f, str) + if err != nil { + errorf("decode: %s", err) + } + return t +} + +var errInvalidTimestamp = errors.New("invalid timestamp") + +type timestampParser struct { + err error +} + +func (p *timestampParser) expect(str string, char byte, pos int) { + if p.err != nil { + return + } + if pos+1 > len(str) { + p.err = errInvalidTimestamp + return + } + if c := str[pos]; c != char && p.err == nil { + p.err = fmt.Errorf("expected '%v' at position %v; got '%v'", char, pos, c) + } +} + +func (p *timestampParser) mustAtoi(str string, begin int, end int) int { + if p.err != nil { + return 0 + } + if begin < 0 || end < 0 || begin > end || end > len(str) { + p.err = errInvalidTimestamp + return 0 + } + result, err := strconv.Atoi(str[begin:end]) + if err != nil { + if p.err == nil { + p.err = fmt.Errorf("expected number; got '%v'", str) + } + return 0 + } + return result +} + +// The location cache caches the time zones typically used by the client. +type locationCache struct { + cache map[int]*time.Location + lock sync.Mutex +} + +// All connections share the same list of timezones. Benchmarking shows that +// about 5% speed could be gained by putting the cache in the connection and +// losing the mutex, at the cost of a small amount of memory and a somewhat +// significant increase in code complexity. +var globalLocationCache = newLocationCache() + +func newLocationCache() *locationCache { + return &locationCache{cache: make(map[int]*time.Location)} +} + +// Returns the cached timezone for the specified offset, creating and caching +// it if necessary. +func (c *locationCache) getLocation(offset int) *time.Location { + c.lock.Lock() + defer c.lock.Unlock() + + location, ok := c.cache[offset] + if !ok { + location = time.FixedZone("", offset) + c.cache[offset] = location + } + + return location +} + +var infinityTsEnabled = false +var infinityTsNegative time.Time +var infinityTsPositive time.Time + +const ( + infinityTsEnabledAlready = "pq: infinity timestamp enabled already" + infinityTsNegativeMustBeSmaller = "pq: infinity timestamp: negative value must be smaller (before) than positive" +) + +// EnableInfinityTs controls the handling of Postgres' "-infinity" and +// "infinity" "timestamp"s. +// +// If EnableInfinityTs is not called, "-infinity" and "infinity" will return +// []byte("-infinity") and []byte("infinity") respectively, and potentially +// cause error "sql: Scan error on column index 0: unsupported driver -> Scan +// pair: []uint8 -> *time.Time", when scanning into a time.Time value. +// +// Once EnableInfinityTs has been called, all connections created using this +// driver will decode Postgres' "-infinity" and "infinity" for "timestamp", +// "timestamp with time zone" and "date" types to the predefined minimum and +// maximum times, respectively. When encoding time.Time values, any time which +// equals or precedes the predefined minimum time will be encoded to +// "-infinity". Any values at or past the maximum time will similarly be +// encoded to "infinity". +// +// If EnableInfinityTs is called with negative >= positive, it will panic. +// Calling EnableInfinityTs after a connection has been established results in +// undefined behavior. If EnableInfinityTs is called more than once, it will +// panic. +func EnableInfinityTs(negative time.Time, positive time.Time) { + if infinityTsEnabled { + panic(infinityTsEnabledAlready) + } + if !negative.Before(positive) { + panic(infinityTsNegativeMustBeSmaller) + } + infinityTsEnabled = true + infinityTsNegative = negative + infinityTsPositive = positive +} + +/* + * Testing might want to toggle infinityTsEnabled + */ +func disableInfinityTs() { + infinityTsEnabled = false +} + +// This is a time function specific to the Postgres default DateStyle +// setting ("ISO, MDY"), the only one we currently support. This +// accounts for the discrepancies between the parsing available with +// time.Parse and the Postgres date formatting quirks. +func parseTs(currentLocation *time.Location, str string) interface{} { + switch str { + case "-infinity": + if infinityTsEnabled { + return infinityTsNegative + } + return []byte(str) + case "infinity": + if infinityTsEnabled { + return infinityTsPositive + } + return []byte(str) + } + t, err := ParseTimestamp(currentLocation, str) + if err != nil { + panic(err) + } + return t +} + +// ParseTimestamp parses Postgres' text format. It returns a time.Time in +// currentLocation iff that time's offset agrees with the offset sent from the +// Postgres server. Otherwise, ParseTimestamp returns a time.Time with the +// fixed offset offset provided by the Postgres server. +func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, error) { + p := timestampParser{} + + monSep := strings.IndexRune(str, '-') + // this is Gregorian year, not ISO Year + // In Gregorian system, the year 1 BC is followed by AD 1 + year := p.mustAtoi(str, 0, monSep) + daySep := monSep + 3 + month := p.mustAtoi(str, monSep+1, daySep) + p.expect(str, '-', daySep) + timeSep := daySep + 3 + day := p.mustAtoi(str, daySep+1, timeSep) + + minLen := monSep + len("01-01") + 1 + + isBC := strings.HasSuffix(str, " BC") + if isBC { + minLen += 3 + } + + var hour, minute, second int + if len(str) > minLen { + p.expect(str, ' ', timeSep) + minSep := timeSep + 3 + p.expect(str, ':', minSep) + hour = p.mustAtoi(str, timeSep+1, minSep) + secSep := minSep + 3 + p.expect(str, ':', secSep) + minute = p.mustAtoi(str, minSep+1, secSep) + secEnd := secSep + 3 + second = p.mustAtoi(str, secSep+1, secEnd) + } + remainderIdx := monSep + len("01-01 00:00:00") + 1 + // Three optional (but ordered) sections follow: the + // fractional seconds, the time zone offset, and the BC + // designation. We set them up here and adjust the other + // offsets if the preceding sections exist. + + nanoSec := 0 + tzOff := 0 + + if remainderIdx < len(str) && str[remainderIdx] == '.' { + fracStart := remainderIdx + 1 + fracOff := strings.IndexAny(str[fracStart:], "-+ ") + if fracOff < 0 { + fracOff = len(str) - fracStart + } + fracSec := p.mustAtoi(str, fracStart, fracStart+fracOff) + nanoSec = fracSec * (1000000000 / int(math.Pow(10, float64(fracOff)))) + + remainderIdx += fracOff + 1 + } + if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart] == '-' || str[tzStart] == '+') { + // time zone separator is always '-' or '+' (UTC is +00) + var tzSign int + switch c := str[tzStart]; c { + case '-': + tzSign = -1 + case '+': + tzSign = +1 + default: + return time.Time{}, fmt.Errorf("expected '-' or '+' at position %v; got %v", tzStart, c) + } + tzHours := p.mustAtoi(str, tzStart+1, tzStart+3) + remainderIdx += 3 + var tzMin, tzSec int + if remainderIdx < len(str) && str[remainderIdx] == ':' { + tzMin = p.mustAtoi(str, remainderIdx+1, remainderIdx+3) + remainderIdx += 3 + } + if remainderIdx < len(str) && str[remainderIdx] == ':' { + tzSec = p.mustAtoi(str, remainderIdx+1, remainderIdx+3) + remainderIdx += 3 + } + tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec) + } + var isoYear int + + if isBC { + isoYear = 1 - year + remainderIdx += 3 + } else { + isoYear = year + } + if remainderIdx < len(str) { + return time.Time{}, fmt.Errorf("expected end of input, got %v", str[remainderIdx:]) + } + t := time.Date(isoYear, time.Month(month), day, + hour, minute, second, nanoSec, + globalLocationCache.getLocation(tzOff)) + + if currentLocation != nil { + // Set the location of the returned Time based on the session's + // TimeZone value, but only if the local time zone database agrees with + // the remote database on the offset. + lt := t.In(currentLocation) + _, newOff := lt.Zone() + if newOff == tzOff { + t = lt + } + } + + return t, p.err +} + +// formatTs formats t into a format postgres understands. +func formatTs(t time.Time) []byte { + if infinityTsEnabled { + // t <= -infinity : ! (t > -infinity) + if !t.After(infinityTsNegative) { + return []byte("-infinity") + } + // t >= infinity : ! (!t < infinity) + if !t.Before(infinityTsPositive) { + return []byte("infinity") + } + } + return FormatTimestamp(t) +} + +// FormatTimestamp formats t into Postgres' text format for timestamps. +func FormatTimestamp(t time.Time) []byte { + // Need to send dates before 0001 A.D. with " BC" suffix, instead of the + // minus sign preferred by Go. + // Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on + bc := false + if t.Year() <= 0 { + // flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11" + t = t.AddDate((-t.Year())*2+1, 0, 0) + bc = true + } + b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00")) + + _, offset := t.Zone() + offset = offset % 60 + if offset != 0 { + // RFC3339Nano already printed the minus sign + if offset < 0 { + offset = -offset + } + + b = append(b, ':') + if offset < 10 { + b = append(b, '0') + } + b = strconv.AppendInt(b, int64(offset), 10) + } + + if bc { + b = append(b, " BC"...) + } + return b +} + +// Parse a bytea value received from the server. Both "hex" and the legacy +// "escape" format are supported. +func parseBytea(s []byte) (result []byte, err error) { + if len(s) >= 2 && bytes.Equal(s[:2], []byte("\\x")) { + // bytea_output = hex + s = s[2:] // trim off leading "\\x" + result = make([]byte, hex.DecodedLen(len(s))) + _, err := hex.Decode(result, s) + if err != nil { + return nil, err + } + } else { + // bytea_output = escape + for len(s) > 0 { + if s[0] == '\\' { + // escaped '\\' + if len(s) >= 2 && s[1] == '\\' { + result = append(result, '\\') + s = s[2:] + continue + } + + // '\\' followed by an octal number + if len(s) < 4 { + return nil, fmt.Errorf("invalid bytea sequence %v", s) + } + r, err := strconv.ParseInt(string(s[1:4]), 8, 9) + if err != nil { + return nil, fmt.Errorf("could not parse bytea value: %s", err.Error()) + } + result = append(result, byte(r)) + s = s[4:] + } else { + // We hit an unescaped, raw byte. Try to read in as many as + // possible in one go. + i := bytes.IndexByte(s, '\\') + if i == -1 { + result = append(result, s...) + break + } + result = append(result, s[:i]...) + s = s[i:] + } + } + } + + return result, nil +} + +func encodeBytea(serverVersion int, v []byte) (result []byte) { + if serverVersion >= 90000 { + // Use the hex format if we know that the server supports it + result = make([]byte, 2+hex.EncodedLen(len(v))) + result[0] = '\\' + result[1] = 'x' + hex.Encode(result[2:], v) + } else { + // .. or resort to "escape" + for _, b := range v { + if b == '\\' { + result = append(result, '\\', '\\') + } else if b < 0x20 || b > 0x7e { + result = append(result, []byte(fmt.Sprintf("\\%03o", b))...) + } else { + result = append(result, b) + } + } + } + + return result +} + +// NullTime represents a time.Time that may be null. NullTime implements the +// sql.Scanner interface so it can be used as a scan destination, similar to +// sql.NullString. +type NullTime struct { + Time time.Time + Valid bool // Valid is true if Time is not NULL +} + +// Scan implements the Scanner interface. +func (nt *NullTime) Scan(value interface{}) error { + nt.Time, nt.Valid = value.(time.Time) + return nil +} + +// Value implements the driver Valuer interface. +func (nt NullTime) Value() (driver.Value, error) { + if !nt.Valid { + return nil, nil + } + return nt.Time, nil +} diff --git a/vendor/github.com/lib/pq/error.go b/vendor/github.com/lib/pq/error.go new file mode 100644 index 000000000..96aae29c6 --- /dev/null +++ b/vendor/github.com/lib/pq/error.go @@ -0,0 +1,515 @@ +package pq + +import ( + "database/sql/driver" + "fmt" + "io" + "net" + "runtime" +) + +// Error severities +const ( + Efatal = "FATAL" + Epanic = "PANIC" + Ewarning = "WARNING" + Enotice = "NOTICE" + Edebug = "DEBUG" + Einfo = "INFO" + Elog = "LOG" +) + +// Error represents an error communicating with the server. +// +// See http://www.postgresql.org/docs/current/static/protocol-error-fields.html for details of the fields +type Error struct { + Severity string + Code ErrorCode + Message string + Detail string + Hint string + Position string + InternalPosition string + InternalQuery string + Where string + Schema string + Table string + Column string + DataTypeName string + Constraint string + File string + Line string + Routine string +} + +// ErrorCode is a five-character error code. +type ErrorCode string + +// Name returns a more human friendly rendering of the error code, namely the +// "condition name". +// +// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for +// details. +func (ec ErrorCode) Name() string { + return errorCodeNames[ec] +} + +// ErrorClass is only the class part of an error code. +type ErrorClass string + +// Name returns the condition name of an error class. It is equivalent to the +// condition name of the "standard" error code (i.e. the one having the last +// three characters "000"). +func (ec ErrorClass) Name() string { + return errorCodeNames[ErrorCode(ec+"000")] +} + +// Class returns the error class, e.g. "28". +// +// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for +// details. +func (ec ErrorCode) Class() ErrorClass { + return ErrorClass(ec[0:2]) +} + +// errorCodeNames is a mapping between the five-character error codes and the +// human readable "condition names". It is derived from the list at +// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html +var errorCodeNames = map[ErrorCode]string{ + // Class 00 - Successful Completion + "00000": "successful_completion", + // Class 01 - Warning + "01000": "warning", + "0100C": "dynamic_result_sets_returned", + "01008": "implicit_zero_bit_padding", + "01003": "null_value_eliminated_in_set_function", + "01007": "privilege_not_granted", + "01006": "privilege_not_revoked", + "01004": "string_data_right_truncation", + "01P01": "deprecated_feature", + // Class 02 - No Data (this is also a warning class per the SQL standard) + "02000": "no_data", + "02001": "no_additional_dynamic_result_sets_returned", + // Class 03 - SQL Statement Not Yet Complete + "03000": "sql_statement_not_yet_complete", + // Class 08 - Connection Exception + "08000": "connection_exception", + "08003": "connection_does_not_exist", + "08006": "connection_failure", + "08001": "sqlclient_unable_to_establish_sqlconnection", + "08004": "sqlserver_rejected_establishment_of_sqlconnection", + "08007": "transaction_resolution_unknown", + "08P01": "protocol_violation", + // Class 09 - Triggered Action Exception + "09000": "triggered_action_exception", + // Class 0A - Feature Not Supported + "0A000": "feature_not_supported", + // Class 0B - Invalid Transaction Initiation + "0B000": "invalid_transaction_initiation", + // Class 0F - Locator Exception + "0F000": "locator_exception", + "0F001": "invalid_locator_specification", + // Class 0L - Invalid Grantor + "0L000": "invalid_grantor", + "0LP01": "invalid_grant_operation", + // Class 0P - Invalid Role Specification + "0P000": "invalid_role_specification", + // Class 0Z - Diagnostics Exception + "0Z000": "diagnostics_exception", + "0Z002": "stacked_diagnostics_accessed_without_active_handler", + // Class 20 - Case Not Found + "20000": "case_not_found", + // Class 21 - Cardinality Violation + "21000": "cardinality_violation", + // Class 22 - Data Exception + "22000": "data_exception", + "2202E": "array_subscript_error", + "22021": "character_not_in_repertoire", + "22008": "datetime_field_overflow", + "22012": "division_by_zero", + "22005": "error_in_assignment", + "2200B": "escape_character_conflict", + "22022": "indicator_overflow", + "22015": "interval_field_overflow", + "2201E": "invalid_argument_for_logarithm", + "22014": "invalid_argument_for_ntile_function", + "22016": "invalid_argument_for_nth_value_function", + "2201F": "invalid_argument_for_power_function", + "2201G": "invalid_argument_for_width_bucket_function", + "22018": "invalid_character_value_for_cast", + "22007": "invalid_datetime_format", + "22019": "invalid_escape_character", + "2200D": "invalid_escape_octet", + "22025": "invalid_escape_sequence", + "22P06": "nonstandard_use_of_escape_character", + "22010": "invalid_indicator_parameter_value", + "22023": "invalid_parameter_value", + "2201B": "invalid_regular_expression", + "2201W": "invalid_row_count_in_limit_clause", + "2201X": "invalid_row_count_in_result_offset_clause", + "22009": "invalid_time_zone_displacement_value", + "2200C": "invalid_use_of_escape_character", + "2200G": "most_specific_type_mismatch", + "22004": "null_value_not_allowed", + "22002": "null_value_no_indicator_parameter", + "22003": "numeric_value_out_of_range", + "2200H": "sequence_generator_limit_exceeded", + "22026": "string_data_length_mismatch", + "22001": "string_data_right_truncation", + "22011": "substring_error", + "22027": "trim_error", + "22024": "unterminated_c_string", + "2200F": "zero_length_character_string", + "22P01": "floating_point_exception", + "22P02": "invalid_text_representation", + "22P03": "invalid_binary_representation", + "22P04": "bad_copy_file_format", + "22P05": "untranslatable_character", + "2200L": "not_an_xml_document", + "2200M": "invalid_xml_document", + "2200N": "invalid_xml_content", + "2200S": "invalid_xml_comment", + "2200T": "invalid_xml_processing_instruction", + // Class 23 - Integrity Constraint Violation + "23000": "integrity_constraint_violation", + "23001": "restrict_violation", + "23502": "not_null_violation", + "23503": "foreign_key_violation", + "23505": "unique_violation", + "23514": "check_violation", + "23P01": "exclusion_violation", + // Class 24 - Invalid Cursor State + "24000": "invalid_cursor_state", + // Class 25 - Invalid Transaction State + "25000": "invalid_transaction_state", + "25001": "active_sql_transaction", + "25002": "branch_transaction_already_active", + "25008": "held_cursor_requires_same_isolation_level", + "25003": "inappropriate_access_mode_for_branch_transaction", + "25004": "inappropriate_isolation_level_for_branch_transaction", + "25005": "no_active_sql_transaction_for_branch_transaction", + "25006": "read_only_sql_transaction", + "25007": "schema_and_data_statement_mixing_not_supported", + "25P01": "no_active_sql_transaction", + "25P02": "in_failed_sql_transaction", + // Class 26 - Invalid SQL Statement Name + "26000": "invalid_sql_statement_name", + // Class 27 - Triggered Data Change Violation + "27000": "triggered_data_change_violation", + // Class 28 - Invalid Authorization Specification + "28000": "invalid_authorization_specification", + "28P01": "invalid_password", + // Class 2B - Dependent Privilege Descriptors Still Exist + "2B000": "dependent_privilege_descriptors_still_exist", + "2BP01": "dependent_objects_still_exist", + // Class 2D - Invalid Transaction Termination + "2D000": "invalid_transaction_termination", + // Class 2F - SQL Routine Exception + "2F000": "sql_routine_exception", + "2F005": "function_executed_no_return_statement", + "2F002": "modifying_sql_data_not_permitted", + "2F003": "prohibited_sql_statement_attempted", + "2F004": "reading_sql_data_not_permitted", + // Class 34 - Invalid Cursor Name + "34000": "invalid_cursor_name", + // Class 38 - External Routine Exception + "38000": "external_routine_exception", + "38001": "containing_sql_not_permitted", + "38002": "modifying_sql_data_not_permitted", + "38003": "prohibited_sql_statement_attempted", + "38004": "reading_sql_data_not_permitted", + // Class 39 - External Routine Invocation Exception + "39000": "external_routine_invocation_exception", + "39001": "invalid_sqlstate_returned", + "39004": "null_value_not_allowed", + "39P01": "trigger_protocol_violated", + "39P02": "srf_protocol_violated", + // Class 3B - Savepoint Exception + "3B000": "savepoint_exception", + "3B001": "invalid_savepoint_specification", + // Class 3D - Invalid Catalog Name + "3D000": "invalid_catalog_name", + // Class 3F - Invalid Schema Name + "3F000": "invalid_schema_name", + // Class 40 - Transaction Rollback + "40000": "transaction_rollback", + "40002": "transaction_integrity_constraint_violation", + "40001": "serialization_failure", + "40003": "statement_completion_unknown", + "40P01": "deadlock_detected", + // Class 42 - Syntax Error or Access Rule Violation + "42000": "syntax_error_or_access_rule_violation", + "42601": "syntax_error", + "42501": "insufficient_privilege", + "42846": "cannot_coerce", + "42803": "grouping_error", + "42P20": "windowing_error", + "42P19": "invalid_recursion", + "42830": "invalid_foreign_key", + "42602": "invalid_name", + "42622": "name_too_long", + "42939": "reserved_name", + "42804": "datatype_mismatch", + "42P18": "indeterminate_datatype", + "42P21": "collation_mismatch", + "42P22": "indeterminate_collation", + "42809": "wrong_object_type", + "42703": "undefined_column", + "42883": "undefined_function", + "42P01": "undefined_table", + "42P02": "undefined_parameter", + "42704": "undefined_object", + "42701": "duplicate_column", + "42P03": "duplicate_cursor", + "42P04": "duplicate_database", + "42723": "duplicate_function", + "42P05": "duplicate_prepared_statement", + "42P06": "duplicate_schema", + "42P07": "duplicate_table", + "42712": "duplicate_alias", + "42710": "duplicate_object", + "42702": "ambiguous_column", + "42725": "ambiguous_function", + "42P08": "ambiguous_parameter", + "42P09": "ambiguous_alias", + "42P10": "invalid_column_reference", + "42611": "invalid_column_definition", + "42P11": "invalid_cursor_definition", + "42P12": "invalid_database_definition", + "42P13": "invalid_function_definition", + "42P14": "invalid_prepared_statement_definition", + "42P15": "invalid_schema_definition", + "42P16": "invalid_table_definition", + "42P17": "invalid_object_definition", + // Class 44 - WITH CHECK OPTION Violation + "44000": "with_check_option_violation", + // Class 53 - Insufficient Resources + "53000": "insufficient_resources", + "53100": "disk_full", + "53200": "out_of_memory", + "53300": "too_many_connections", + "53400": "configuration_limit_exceeded", + // Class 54 - Program Limit Exceeded + "54000": "program_limit_exceeded", + "54001": "statement_too_complex", + "54011": "too_many_columns", + "54023": "too_many_arguments", + // Class 55 - Object Not In Prerequisite State + "55000": "object_not_in_prerequisite_state", + "55006": "object_in_use", + "55P02": "cant_change_runtime_param", + "55P03": "lock_not_available", + // Class 57 - Operator Intervention + "57000": "operator_intervention", + "57014": "query_canceled", + "57P01": "admin_shutdown", + "57P02": "crash_shutdown", + "57P03": "cannot_connect_now", + "57P04": "database_dropped", + // Class 58 - System Error (errors external to PostgreSQL itself) + "58000": "system_error", + "58030": "io_error", + "58P01": "undefined_file", + "58P02": "duplicate_file", + // Class F0 - Configuration File Error + "F0000": "config_file_error", + "F0001": "lock_file_exists", + // Class HV - Foreign Data Wrapper Error (SQL/MED) + "HV000": "fdw_error", + "HV005": "fdw_column_name_not_found", + "HV002": "fdw_dynamic_parameter_value_needed", + "HV010": "fdw_function_sequence_error", + "HV021": "fdw_inconsistent_descriptor_information", + "HV024": "fdw_invalid_attribute_value", + "HV007": "fdw_invalid_column_name", + "HV008": "fdw_invalid_column_number", + "HV004": "fdw_invalid_data_type", + "HV006": "fdw_invalid_data_type_descriptors", + "HV091": "fdw_invalid_descriptor_field_identifier", + "HV00B": "fdw_invalid_handle", + "HV00C": "fdw_invalid_option_index", + "HV00D": "fdw_invalid_option_name", + "HV090": "fdw_invalid_string_length_or_buffer_length", + "HV00A": "fdw_invalid_string_format", + "HV009": "fdw_invalid_use_of_null_pointer", + "HV014": "fdw_too_many_handles", + "HV001": "fdw_out_of_memory", + "HV00P": "fdw_no_schemas", + "HV00J": "fdw_option_name_not_found", + "HV00K": "fdw_reply_handle", + "HV00Q": "fdw_schema_not_found", + "HV00R": "fdw_table_not_found", + "HV00L": "fdw_unable_to_create_execution", + "HV00M": "fdw_unable_to_create_reply", + "HV00N": "fdw_unable_to_establish_connection", + // Class P0 - PL/pgSQL Error + "P0000": "plpgsql_error", + "P0001": "raise_exception", + "P0002": "no_data_found", + "P0003": "too_many_rows", + // Class XX - Internal Error + "XX000": "internal_error", + "XX001": "data_corrupted", + "XX002": "index_corrupted", +} + +func parseError(r *readBuf) *Error { + err := new(Error) + for t := r.byte(); t != 0; t = r.byte() { + msg := r.string() + switch t { + case 'S': + err.Severity = msg + case 'C': + err.Code = ErrorCode(msg) + case 'M': + err.Message = msg + case 'D': + err.Detail = msg + case 'H': + err.Hint = msg + case 'P': + err.Position = msg + case 'p': + err.InternalPosition = msg + case 'q': + err.InternalQuery = msg + case 'W': + err.Where = msg + case 's': + err.Schema = msg + case 't': + err.Table = msg + case 'c': + err.Column = msg + case 'd': + err.DataTypeName = msg + case 'n': + err.Constraint = msg + case 'F': + err.File = msg + case 'L': + err.Line = msg + case 'R': + err.Routine = msg + } + } + return err +} + +// Fatal returns true if the Error Severity is fatal. +func (err *Error) Fatal() bool { + return err.Severity == Efatal +} + +// Get implements the legacy PGError interface. New code should use the fields +// of the Error struct directly. +func (err *Error) Get(k byte) (v string) { + switch k { + case 'S': + return err.Severity + case 'C': + return string(err.Code) + case 'M': + return err.Message + case 'D': + return err.Detail + case 'H': + return err.Hint + case 'P': + return err.Position + case 'p': + return err.InternalPosition + case 'q': + return err.InternalQuery + case 'W': + return err.Where + case 's': + return err.Schema + case 't': + return err.Table + case 'c': + return err.Column + case 'd': + return err.DataTypeName + case 'n': + return err.Constraint + case 'F': + return err.File + case 'L': + return err.Line + case 'R': + return err.Routine + } + return "" +} + +func (err Error) Error() string { + return "pq: " + err.Message +} + +// PGError is an interface used by previous versions of pq. It is provided +// only to support legacy code. New code should use the Error type. +type PGError interface { + Error() string + Fatal() bool + Get(k byte) (v string) +} + +func errorf(s string, args ...interface{}) { + panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) +} + +// TODO(ainar-g) Rename to errorf after removing panics. +func fmterrorf(s string, args ...interface{}) error { + return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)) +} + +func errRecoverNoErrBadConn(err *error) { + e := recover() + if e == nil { + // Do nothing + return + } + var ok bool + *err, ok = e.(error) + if !ok { + *err = fmt.Errorf("pq: unexpected error: %#v", e) + } +} + +func (c *conn) errRecover(err *error) { + e := recover() + switch v := e.(type) { + case nil: + // Do nothing + case runtime.Error: + c.bad = true + panic(v) + case *Error: + if v.Fatal() { + *err = driver.ErrBadConn + } else { + *err = v + } + case *net.OpError: + c.bad = true + *err = v + case error: + if v == io.EOF || v.(error).Error() == "remote error: handshake failure" { + *err = driver.ErrBadConn + } else { + *err = v + } + + default: + c.bad = true + panic(fmt.Sprintf("unknown error: %#v", e)) + } + + // Any time we return ErrBadConn, we need to remember it since *Tx doesn't + // mark the connection bad in database/sql. + if *err == driver.ErrBadConn { + c.bad = true + } +} diff --git a/vendor/github.com/lib/pq/notify.go b/vendor/github.com/lib/pq/notify.go new file mode 100644 index 000000000..947d189f4 --- /dev/null +++ b/vendor/github.com/lib/pq/notify.go @@ -0,0 +1,794 @@ +package pq + +// Package pq is a pure Go Postgres driver for the database/sql package. +// This module contains support for Postgres LISTEN/NOTIFY. + +import ( + "errors" + "fmt" + "sync" + "sync/atomic" + "time" +) + +// Notification represents a single notification from the database. +type Notification struct { + // Process ID (PID) of the notifying postgres backend. + BePid int + // Name of the channel the notification was sent on. + Channel string + // Payload, or the empty string if unspecified. + Extra string +} + +func recvNotification(r *readBuf) *Notification { + bePid := r.int32() + channel := r.string() + extra := r.string() + + return &Notification{bePid, channel, extra} +} + +const ( + connStateIdle int32 = iota + connStateExpectResponse + connStateExpectReadyForQuery +) + +type message struct { + typ byte + err error +} + +var errListenerConnClosed = errors.New("pq: ListenerConn has been closed") + +// ListenerConn is a low-level interface for waiting for notifications. You +// should use Listener instead. +type ListenerConn struct { + // guards cn and err + connectionLock sync.Mutex + cn *conn + err error + + connState int32 + + // the sending goroutine will be holding this lock + senderLock sync.Mutex + + notificationChan chan<- *Notification + + replyChan chan message +} + +// NewListenerConn creates a new ListenerConn. Use NewListener instead. +func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) { + return newDialListenerConn(defaultDialer{}, name, notificationChan) +} + +func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) { + cn, err := DialOpen(d, name) + if err != nil { + return nil, err + } + + l := &ListenerConn{ + cn: cn.(*conn), + notificationChan: c, + connState: connStateIdle, + replyChan: make(chan message, 2), + } + + go l.listenerConnMain() + + return l, nil +} + +// We can only allow one goroutine at a time to be running a query on the +// connection for various reasons, so the goroutine sending on the connection +// must be holding senderLock. +// +// Returns an error if an unrecoverable error has occurred and the ListenerConn +// should be abandoned. +func (l *ListenerConn) acquireSenderLock() error { + // we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery + l.senderLock.Lock() + + l.connectionLock.Lock() + err := l.err + l.connectionLock.Unlock() + if err != nil { + l.senderLock.Unlock() + return err + } + return nil +} + +func (l *ListenerConn) releaseSenderLock() { + l.senderLock.Unlock() +} + +// setState advances the protocol state to newState. Returns false if moving +// to that state from the current state is not allowed. +func (l *ListenerConn) setState(newState int32) bool { + var expectedState int32 + + switch newState { + case connStateIdle: + expectedState = connStateExpectReadyForQuery + case connStateExpectResponse: + expectedState = connStateIdle + case connStateExpectReadyForQuery: + expectedState = connStateExpectResponse + default: + panic(fmt.Sprintf("unexpected listenerConnState %d", newState)) + } + + return atomic.CompareAndSwapInt32(&l.connState, expectedState, newState) +} + +// Main logic is here: receive messages from the postgres backend, forward +// notifications and query replies and keep the internal state in sync with the +// protocol state. Returns when the connection has been lost, is about to go +// away or should be discarded because we couldn't agree on the state with the +// server backend. +func (l *ListenerConn) listenerConnLoop() (err error) { + defer errRecoverNoErrBadConn(&err) + + r := &readBuf{} + for { + t, err := l.cn.recvMessage(r) + if err != nil { + return err + } + + switch t { + case 'A': + // recvNotification copies all the data so we don't need to worry + // about the scratch buffer being overwritten. + l.notificationChan <- recvNotification(r) + + case 'T', 'D': + // only used by tests; ignore + + case 'E': + // We might receive an ErrorResponse even when not in a query; it + // is expected that the server will close the connection after + // that, but we should make sure that the error we display is the + // one from the stray ErrorResponse, not io.ErrUnexpectedEOF. + if !l.setState(connStateExpectReadyForQuery) { + return parseError(r) + } + l.replyChan <- message{t, parseError(r)} + + case 'C', 'I': + if !l.setState(connStateExpectReadyForQuery) { + // protocol out of sync + return fmt.Errorf("unexpected CommandComplete") + } + // ExecSimpleQuery doesn't need to know about this message + + case 'Z': + if !l.setState(connStateIdle) { + // protocol out of sync + return fmt.Errorf("unexpected ReadyForQuery") + } + l.replyChan <- message{t, nil} + + case 'N', 'S': + // ignore + default: + return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t) + } + } +} + +// This is the main routine for the goroutine receiving on the database +// connection. Most of the main logic is in listenerConnLoop. +func (l *ListenerConn) listenerConnMain() { + err := l.listenerConnLoop() + + // listenerConnLoop terminated; we're done, but we still have to clean up. + // Make sure nobody tries to start any new queries by making sure the err + // pointer is set. It is important that we do not overwrite its value; a + // connection could be closed by either this goroutine or one sending on + // the connection -- whoever closes the connection is assumed to have the + // more meaningful error message (as the other one will probably get + // net.errClosed), so that goroutine sets the error we expose while the + // other error is discarded. If the connection is lost while two + // goroutines are operating on the socket, it probably doesn't matter which + // error we expose so we don't try to do anything more complex. + l.connectionLock.Lock() + if l.err == nil { + l.err = err + } + l.cn.Close() + l.connectionLock.Unlock() + + // There might be a query in-flight; make sure nobody's waiting for a + // response to it, since there's not going to be one. + close(l.replyChan) + + // let the listener know we're done + close(l.notificationChan) + + // this ListenerConn is done +} + +// Listen sends a LISTEN query to the server. See ExecSimpleQuery. +func (l *ListenerConn) Listen(channel string) (bool, error) { + return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel)) +} + +// Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery. +func (l *ListenerConn) Unlisten(channel string) (bool, error) { + return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel)) +} + +// UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery. +func (l *ListenerConn) UnlistenAll() (bool, error) { + return l.ExecSimpleQuery("UNLISTEN *") +} + +// Ping the remote server to make sure it's alive. Non-nil error means the +// connection has failed and should be abandoned. +func (l *ListenerConn) Ping() error { + sent, err := l.ExecSimpleQuery("") + if !sent { + return err + } + if err != nil { + // shouldn't happen + panic(err) + } + return nil +} + +// Attempt to send a query on the connection. Returns an error if sending the +// query failed, and the caller should initiate closure of this connection. +// The caller must be holding senderLock (see acquireSenderLock and +// releaseSenderLock). +func (l *ListenerConn) sendSimpleQuery(q string) (err error) { + defer errRecoverNoErrBadConn(&err) + + // must set connection state before sending the query + if !l.setState(connStateExpectResponse) { + panic("two queries running at the same time") + } + + // Can't use l.cn.writeBuf here because it uses the scratch buffer which + // might get overwritten by listenerConnLoop. + b := &writeBuf{ + buf: []byte("Q\x00\x00\x00\x00"), + pos: 1, + } + b.string(q) + l.cn.send(b) + + return nil +} + +// ExecSimpleQuery executes a "simple query" (i.e. one with no bindable +// parameters) on the connection. The possible return values are: +// 1) "executed" is true; the query was executed to completion on the +// database server. If the query failed, err will be set to the error +// returned by the database, otherwise err will be nil. +// 2) If "executed" is false, the query could not be executed on the remote +// server. err will be non-nil. +// +// After a call to ExecSimpleQuery has returned an executed=false value, the +// connection has either been closed or will be closed shortly thereafter, and +// all subsequently executed queries will return an error. +func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) { + if err = l.acquireSenderLock(); err != nil { + return false, err + } + defer l.releaseSenderLock() + + err = l.sendSimpleQuery(q) + if err != nil { + // We can't know what state the protocol is in, so we need to abandon + // this connection. + l.connectionLock.Lock() + // Set the error pointer if it hasn't been set already; see + // listenerConnMain. + if l.err == nil { + l.err = err + } + l.connectionLock.Unlock() + l.cn.c.Close() + return false, err + } + + // now we just wait for a reply.. + for { + m, ok := <-l.replyChan + if !ok { + // We lost the connection to server, don't bother waiting for a + // a response. err should have been set already. + l.connectionLock.Lock() + err := l.err + l.connectionLock.Unlock() + return false, err + } + switch m.typ { + case 'Z': + // sanity check + if m.err != nil { + panic("m.err != nil") + } + // done; err might or might not be set + return true, err + + case 'E': + // sanity check + if m.err == nil { + panic("m.err == nil") + } + // server responded with an error; ReadyForQuery to follow + err = m.err + + default: + return false, fmt.Errorf("unknown response for simple query: %q", m.typ) + } + } +} + +// Close closes the connection. +func (l *ListenerConn) Close() error { + l.connectionLock.Lock() + if l.err != nil { + l.connectionLock.Unlock() + return errListenerConnClosed + } + l.err = errListenerConnClosed + l.connectionLock.Unlock() + // We can't send anything on the connection without holding senderLock. + // Simply close the net.Conn to wake up everyone operating on it. + return l.cn.c.Close() +} + +// Err returns the reason the connection was closed. It is not safe to call +// this function until l.Notify has been closed. +func (l *ListenerConn) Err() error { + return l.err +} + +var errListenerClosed = errors.New("pq: Listener has been closed") + +// ErrChannelAlreadyOpen is returned from Listen when a channel is already +// open. +var ErrChannelAlreadyOpen = errors.New("pq: channel is already open") + +// ErrChannelNotOpen is returned from Unlisten when a channel is not open. +var ErrChannelNotOpen = errors.New("pq: channel is not open") + +// ListenerEventType is an enumeration of listener event types. +type ListenerEventType int + +const ( + // ListenerEventConnected is emitted only when the database connection + // has been initially initialized. The err argument of the callback + // will always be nil. + ListenerEventConnected ListenerEventType = iota + + // ListenerEventDisconnected is emitted after a database connection has + // been lost, either because of an error or because Close has been + // called. The err argument will be set to the reason the database + // connection was lost. + ListenerEventDisconnected + + // ListenerEventReconnected is emitted after a database connection has + // been re-established after connection loss. The err argument of the + // callback will always be nil. After this event has been emitted, a + // nil pq.Notification is sent on the Listener.Notify channel. + ListenerEventReconnected + + // ListenerEventConnectionAttemptFailed is emitted after a connection + // to the database was attempted, but failed. The err argument will be + // set to an error describing why the connection attempt did not + // succeed. + ListenerEventConnectionAttemptFailed +) + +// EventCallbackType is the event callback type. See also ListenerEventType +// constants' documentation. +type EventCallbackType func(event ListenerEventType, err error) + +// Listener provides an interface for listening to notifications from a +// PostgreSQL database. For general usage information, see section +// "Notifications". +// +// Listener can safely be used from concurrently running goroutines. +type Listener struct { + // Channel for receiving notifications from the database. In some cases a + // nil value will be sent. See section "Notifications" above. + Notify chan *Notification + + name string + minReconnectInterval time.Duration + maxReconnectInterval time.Duration + dialer Dialer + eventCallback EventCallbackType + + lock sync.Mutex + isClosed bool + reconnectCond *sync.Cond + cn *ListenerConn + connNotificationChan <-chan *Notification + channels map[string]struct{} +} + +// NewListener creates a new database connection dedicated to LISTEN / NOTIFY. +// +// name should be set to a connection string to be used to establish the +// database connection (see section "Connection String Parameters" above). +// +// minReconnectInterval controls the duration to wait before trying to +// re-establish the database connection after connection loss. After each +// consecutive failure this interval is doubled, until maxReconnectInterval is +// reached. Successfully completing the connection establishment procedure +// resets the interval back to minReconnectInterval. +// +// The last parameter eventCallback can be set to a function which will be +// called by the Listener when the state of the underlying database connection +// changes. This callback will be called by the goroutine which dispatches the +// notifications over the Notify channel, so you should try to avoid doing +// potentially time-consuming operations from the callback. +func NewListener(name string, + minReconnectInterval time.Duration, + maxReconnectInterval time.Duration, + eventCallback EventCallbackType) *Listener { + return NewDialListener(defaultDialer{}, name, minReconnectInterval, maxReconnectInterval, eventCallback) +} + +// NewDialListener is like NewListener but it takes a Dialer. +func NewDialListener(d Dialer, + name string, + minReconnectInterval time.Duration, + maxReconnectInterval time.Duration, + eventCallback EventCallbackType) *Listener { + + l := &Listener{ + name: name, + minReconnectInterval: minReconnectInterval, + maxReconnectInterval: maxReconnectInterval, + dialer: d, + eventCallback: eventCallback, + + channels: make(map[string]struct{}), + + Notify: make(chan *Notification, 32), + } + l.reconnectCond = sync.NewCond(&l.lock) + + go l.listenerMain() + + return l +} + +// NotificationChannel returns the notification channel for this listener. +// This is the same channel as Notify, and will not be recreated during the +// life time of the Listener. +func (l *Listener) NotificationChannel() <-chan *Notification { + return l.Notify +} + +// Listen starts listening for notifications on a channel. Calls to this +// function will block until an acknowledgement has been received from the +// server. Note that Listener automatically re-establishes the connection +// after connection loss, so this function may block indefinitely if the +// connection can not be re-established. +// +// Listen will only fail in three conditions: +// 1) The channel is already open. The returned error will be +// ErrChannelAlreadyOpen. +// 2) The query was executed on the remote server, but PostgreSQL returned an +// error message in response to the query. The returned error will be a +// pq.Error containing the information the server supplied. +// 3) Close is called on the Listener before the request could be completed. +// +// The channel name is case-sensitive. +func (l *Listener) Listen(channel string) error { + l.lock.Lock() + defer l.lock.Unlock() + + if l.isClosed { + return errListenerClosed + } + + // The server allows you to issue a LISTEN on a channel which is already + // open, but it seems useful to be able to detect this case to spot for + // mistakes in application logic. If the application genuinely does't + // care, it can check the exported error and ignore it. + _, exists := l.channels[channel] + if exists { + return ErrChannelAlreadyOpen + } + + if l.cn != nil { + // If gotResponse is true but error is set, the query was executed on + // the remote server, but resulted in an error. This should be + // relatively rare, so it's fine if we just pass the error to our + // caller. However, if gotResponse is false, we could not complete the + // query on the remote server and our underlying connection is about + // to go away, so we only add relname to l.channels, and wait for + // resync() to take care of the rest. + gotResponse, err := l.cn.Listen(channel) + if gotResponse && err != nil { + return err + } + } + + l.channels[channel] = struct{}{} + for l.cn == nil { + l.reconnectCond.Wait() + // we let go of the mutex for a while + if l.isClosed { + return errListenerClosed + } + } + + return nil +} + +// Unlisten removes a channel from the Listener's channel list. Returns +// ErrChannelNotOpen if the Listener is not listening on the specified channel. +// Returns immediately with no error if there is no connection. Note that you +// might still get notifications for this channel even after Unlisten has +// returned. +// +// The channel name is case-sensitive. +func (l *Listener) Unlisten(channel string) error { + l.lock.Lock() + defer l.lock.Unlock() + + if l.isClosed { + return errListenerClosed + } + + // Similarly to LISTEN, this is not an error in Postgres, but it seems + // useful to distinguish from the normal conditions. + _, exists := l.channels[channel] + if !exists { + return ErrChannelNotOpen + } + + if l.cn != nil { + // Similarly to Listen (see comment in that function), the caller + // should only be bothered with an error if it came from the backend as + // a response to our query. + gotResponse, err := l.cn.Unlisten(channel) + if gotResponse && err != nil { + return err + } + } + + // Don't bother waiting for resync if there's no connection. + delete(l.channels, channel) + return nil +} + +// UnlistenAll removes all channels from the Listener's channel list. Returns +// immediately with no error if there is no connection. Note that you might +// still get notifications for any of the deleted channels even after +// UnlistenAll has returned. +func (l *Listener) UnlistenAll() error { + l.lock.Lock() + defer l.lock.Unlock() + + if l.isClosed { + return errListenerClosed + } + + if l.cn != nil { + // Similarly to Listen (see comment in that function), the caller + // should only be bothered with an error if it came from the backend as + // a response to our query. + gotResponse, err := l.cn.UnlistenAll() + if gotResponse && err != nil { + return err + } + } + + // Don't bother waiting for resync if there's no connection. + l.channels = make(map[string]struct{}) + return nil +} + +// Ping the remote server to make sure it's alive. Non-nil return value means +// that there is no active connection. +func (l *Listener) Ping() error { + l.lock.Lock() + defer l.lock.Unlock() + + if l.isClosed { + return errListenerClosed + } + if l.cn == nil { + return errors.New("no connection") + } + + return l.cn.Ping() +} + +// Clean up after losing the server connection. Returns l.cn.Err(), which +// should have the reason the connection was lost. +func (l *Listener) disconnectCleanup() error { + l.lock.Lock() + defer l.lock.Unlock() + + // sanity check; can't look at Err() until the channel has been closed + select { + case _, ok := <-l.connNotificationChan: + if ok { + panic("connNotificationChan not closed") + } + default: + panic("connNotificationChan not closed") + } + + err := l.cn.Err() + l.cn.Close() + l.cn = nil + return err +} + +// Synchronize the list of channels we want to be listening on with the server +// after the connection has been established. +func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error { + doneChan := make(chan error) + go func(notificationChan <-chan *Notification) { + for channel := range l.channels { + // If we got a response, return that error to our caller as it's + // going to be more descriptive than cn.Err(). + gotResponse, err := cn.Listen(channel) + if gotResponse && err != nil { + doneChan <- err + return + } + + // If we couldn't reach the server, wait for notificationChan to + // close and then return the error message from the connection, as + // per ListenerConn's interface. + if err != nil { + for range notificationChan { + } + doneChan <- cn.Err() + return + } + } + doneChan <- nil + }(notificationChan) + + // Ignore notifications while synchronization is going on to avoid + // deadlocks. We have to send a nil notification over Notify anyway as + // we can't possibly know which notifications (if any) were lost while + // the connection was down, so there's no reason to try and process + // these messages at all. + for { + select { + case _, ok := <-notificationChan: + if !ok { + notificationChan = nil + } + + case err := <-doneChan: + return err + } + } +} + +// caller should NOT be holding l.lock +func (l *Listener) closed() bool { + l.lock.Lock() + defer l.lock.Unlock() + + return l.isClosed +} + +func (l *Listener) connect() error { + notificationChan := make(chan *Notification, 32) + cn, err := newDialListenerConn(l.dialer, l.name, notificationChan) + if err != nil { + return err + } + + l.lock.Lock() + defer l.lock.Unlock() + + err = l.resync(cn, notificationChan) + if err != nil { + cn.Close() + return err + } + + l.cn = cn + l.connNotificationChan = notificationChan + l.reconnectCond.Broadcast() + + return nil +} + +// Close disconnects the Listener from the database and shuts it down. +// Subsequent calls to its methods will return an error. Close returns an +// error if the connection has already been closed. +func (l *Listener) Close() error { + l.lock.Lock() + defer l.lock.Unlock() + + if l.isClosed { + return errListenerClosed + } + + if l.cn != nil { + l.cn.Close() + } + l.isClosed = true + + return nil +} + +func (l *Listener) emitEvent(event ListenerEventType, err error) { + if l.eventCallback != nil { + l.eventCallback(event, err) + } +} + +// Main logic here: maintain a connection to the server when possible, wait +// for notifications and emit events. +func (l *Listener) listenerConnLoop() { + var nextReconnect time.Time + + reconnectInterval := l.minReconnectInterval + for { + for { + err := l.connect() + if err == nil { + break + } + + if l.closed() { + return + } + l.emitEvent(ListenerEventConnectionAttemptFailed, err) + + time.Sleep(reconnectInterval) + reconnectInterval *= 2 + if reconnectInterval > l.maxReconnectInterval { + reconnectInterval = l.maxReconnectInterval + } + } + + if nextReconnect.IsZero() { + l.emitEvent(ListenerEventConnected, nil) + } else { + l.emitEvent(ListenerEventReconnected, nil) + l.Notify <- nil + } + + reconnectInterval = l.minReconnectInterval + nextReconnect = time.Now().Add(reconnectInterval) + + for { + notification, ok := <-l.connNotificationChan + if !ok { + // lost connection, loop again + break + } + l.Notify <- notification + } + + err := l.disconnectCleanup() + if l.closed() { + return + } + l.emitEvent(ListenerEventDisconnected, err) + + time.Sleep(time.Until(nextReconnect)) + } +} + +func (l *Listener) listenerMain() { + l.listenerConnLoop() + close(l.Notify) +} diff --git a/vendor/github.com/lib/pq/oid/doc.go b/vendor/github.com/lib/pq/oid/doc.go new file mode 100644 index 000000000..caaede248 --- /dev/null +++ b/vendor/github.com/lib/pq/oid/doc.go @@ -0,0 +1,6 @@ +// Package oid contains OID constants +// as defined by the Postgres server. +package oid + +// Oid is a Postgres Object ID. +type Oid uint32 diff --git a/vendor/github.com/lib/pq/oid/types.go b/vendor/github.com/lib/pq/oid/types.go new file mode 100644 index 000000000..ecc84c2c8 --- /dev/null +++ b/vendor/github.com/lib/pq/oid/types.go @@ -0,0 +1,343 @@ +// Code generated by gen.go. DO NOT EDIT. + +package oid + +const ( + T_bool Oid = 16 + T_bytea Oid = 17 + T_char Oid = 18 + T_name Oid = 19 + T_int8 Oid = 20 + T_int2 Oid = 21 + T_int2vector Oid = 22 + T_int4 Oid = 23 + T_regproc Oid = 24 + T_text Oid = 25 + T_oid Oid = 26 + T_tid Oid = 27 + T_xid Oid = 28 + T_cid Oid = 29 + T_oidvector Oid = 30 + T_pg_ddl_command Oid = 32 + T_pg_type Oid = 71 + T_pg_attribute Oid = 75 + T_pg_proc Oid = 81 + T_pg_class Oid = 83 + T_json Oid = 114 + T_xml Oid = 142 + T__xml Oid = 143 + T_pg_node_tree Oid = 194 + T__json Oid = 199 + T_smgr Oid = 210 + T_index_am_handler Oid = 325 + T_point Oid = 600 + T_lseg Oid = 601 + T_path Oid = 602 + T_box Oid = 603 + T_polygon Oid = 604 + T_line Oid = 628 + T__line Oid = 629 + T_cidr Oid = 650 + T__cidr Oid = 651 + T_float4 Oid = 700 + T_float8 Oid = 701 + T_abstime Oid = 702 + T_reltime Oid = 703 + T_tinterval Oid = 704 + T_unknown Oid = 705 + T_circle Oid = 718 + T__circle Oid = 719 + T_money Oid = 790 + T__money Oid = 791 + T_macaddr Oid = 829 + T_inet Oid = 869 + T__bool Oid = 1000 + T__bytea Oid = 1001 + T__char Oid = 1002 + T__name Oid = 1003 + T__int2 Oid = 1005 + T__int2vector Oid = 1006 + T__int4 Oid = 1007 + T__regproc Oid = 1008 + T__text Oid = 1009 + T__tid Oid = 1010 + T__xid Oid = 1011 + T__cid Oid = 1012 + T__oidvector Oid = 1013 + T__bpchar Oid = 1014 + T__varchar Oid = 1015 + T__int8 Oid = 1016 + T__point Oid = 1017 + T__lseg Oid = 1018 + T__path Oid = 1019 + T__box Oid = 1020 + T__float4 Oid = 1021 + T__float8 Oid = 1022 + T__abstime Oid = 1023 + T__reltime Oid = 1024 + T__tinterval Oid = 1025 + T__polygon Oid = 1027 + T__oid Oid = 1028 + T_aclitem Oid = 1033 + T__aclitem Oid = 1034 + T__macaddr Oid = 1040 + T__inet Oid = 1041 + T_bpchar Oid = 1042 + T_varchar Oid = 1043 + T_date Oid = 1082 + T_time Oid = 1083 + T_timestamp Oid = 1114 + T__timestamp Oid = 1115 + T__date Oid = 1182 + T__time Oid = 1183 + T_timestamptz Oid = 1184 + T__timestamptz Oid = 1185 + T_interval Oid = 1186 + T__interval Oid = 1187 + T__numeric Oid = 1231 + T_pg_database Oid = 1248 + T__cstring Oid = 1263 + T_timetz Oid = 1266 + T__timetz Oid = 1270 + T_bit Oid = 1560 + T__bit Oid = 1561 + T_varbit Oid = 1562 + T__varbit Oid = 1563 + T_numeric Oid = 1700 + T_refcursor Oid = 1790 + T__refcursor Oid = 2201 + T_regprocedure Oid = 2202 + T_regoper Oid = 2203 + T_regoperator Oid = 2204 + T_regclass Oid = 2205 + T_regtype Oid = 2206 + T__regprocedure Oid = 2207 + T__regoper Oid = 2208 + T__regoperator Oid = 2209 + T__regclass Oid = 2210 + T__regtype Oid = 2211 + T_record Oid = 2249 + T_cstring Oid = 2275 + T_any Oid = 2276 + T_anyarray Oid = 2277 + T_void Oid = 2278 + T_trigger Oid = 2279 + T_language_handler Oid = 2280 + T_internal Oid = 2281 + T_opaque Oid = 2282 + T_anyelement Oid = 2283 + T__record Oid = 2287 + T_anynonarray Oid = 2776 + T_pg_authid Oid = 2842 + T_pg_auth_members Oid = 2843 + T__txid_snapshot Oid = 2949 + T_uuid Oid = 2950 + T__uuid Oid = 2951 + T_txid_snapshot Oid = 2970 + T_fdw_handler Oid = 3115 + T_pg_lsn Oid = 3220 + T__pg_lsn Oid = 3221 + T_tsm_handler Oid = 3310 + T_anyenum Oid = 3500 + T_tsvector Oid = 3614 + T_tsquery Oid = 3615 + T_gtsvector Oid = 3642 + T__tsvector Oid = 3643 + T__gtsvector Oid = 3644 + T__tsquery Oid = 3645 + T_regconfig Oid = 3734 + T__regconfig Oid = 3735 + T_regdictionary Oid = 3769 + T__regdictionary Oid = 3770 + T_jsonb Oid = 3802 + T__jsonb Oid = 3807 + T_anyrange Oid = 3831 + T_event_trigger Oid = 3838 + T_int4range Oid = 3904 + T__int4range Oid = 3905 + T_numrange Oid = 3906 + T__numrange Oid = 3907 + T_tsrange Oid = 3908 + T__tsrange Oid = 3909 + T_tstzrange Oid = 3910 + T__tstzrange Oid = 3911 + T_daterange Oid = 3912 + T__daterange Oid = 3913 + T_int8range Oid = 3926 + T__int8range Oid = 3927 + T_pg_shseclabel Oid = 4066 + T_regnamespace Oid = 4089 + T__regnamespace Oid = 4090 + T_regrole Oid = 4096 + T__regrole Oid = 4097 +) + +var TypeName = map[Oid]string{ + T_bool: "BOOL", + T_bytea: "BYTEA", + T_char: "CHAR", + T_name: "NAME", + T_int8: "INT8", + T_int2: "INT2", + T_int2vector: "INT2VECTOR", + T_int4: "INT4", + T_regproc: "REGPROC", + T_text: "TEXT", + T_oid: "OID", + T_tid: "TID", + T_xid: "XID", + T_cid: "CID", + T_oidvector: "OIDVECTOR", + T_pg_ddl_command: "PG_DDL_COMMAND", + T_pg_type: "PG_TYPE", + T_pg_attribute: "PG_ATTRIBUTE", + T_pg_proc: "PG_PROC", + T_pg_class: "PG_CLASS", + T_json: "JSON", + T_xml: "XML", + T__xml: "_XML", + T_pg_node_tree: "PG_NODE_TREE", + T__json: "_JSON", + T_smgr: "SMGR", + T_index_am_handler: "INDEX_AM_HANDLER", + T_point: "POINT", + T_lseg: "LSEG", + T_path: "PATH", + T_box: "BOX", + T_polygon: "POLYGON", + T_line: "LINE", + T__line: "_LINE", + T_cidr: "CIDR", + T__cidr: "_CIDR", + T_float4: "FLOAT4", + T_float8: "FLOAT8", + T_abstime: "ABSTIME", + T_reltime: "RELTIME", + T_tinterval: "TINTERVAL", + T_unknown: "UNKNOWN", + T_circle: "CIRCLE", + T__circle: "_CIRCLE", + T_money: "MONEY", + T__money: "_MONEY", + T_macaddr: "MACADDR", + T_inet: "INET", + T__bool: "_BOOL", + T__bytea: "_BYTEA", + T__char: "_CHAR", + T__name: "_NAME", + T__int2: "_INT2", + T__int2vector: "_INT2VECTOR", + T__int4: "_INT4", + T__regproc: "_REGPROC", + T__text: "_TEXT", + T__tid: "_TID", + T__xid: "_XID", + T__cid: "_CID", + T__oidvector: "_OIDVECTOR", + T__bpchar: "_BPCHAR", + T__varchar: "_VARCHAR", + T__int8: "_INT8", + T__point: "_POINT", + T__lseg: "_LSEG", + T__path: "_PATH", + T__box: "_BOX", + T__float4: "_FLOAT4", + T__float8: "_FLOAT8", + T__abstime: "_ABSTIME", + T__reltime: "_RELTIME", + T__tinterval: "_TINTERVAL", + T__polygon: "_POLYGON", + T__oid: "_OID", + T_aclitem: "ACLITEM", + T__aclitem: "_ACLITEM", + T__macaddr: "_MACADDR", + T__inet: "_INET", + T_bpchar: "BPCHAR", + T_varchar: "VARCHAR", + T_date: "DATE", + T_time: "TIME", + T_timestamp: "TIMESTAMP", + T__timestamp: "_TIMESTAMP", + T__date: "_DATE", + T__time: "_TIME", + T_timestamptz: "TIMESTAMPTZ", + T__timestamptz: "_TIMESTAMPTZ", + T_interval: "INTERVAL", + T__interval: "_INTERVAL", + T__numeric: "_NUMERIC", + T_pg_database: "PG_DATABASE", + T__cstring: "_CSTRING", + T_timetz: "TIMETZ", + T__timetz: "_TIMETZ", + T_bit: "BIT", + T__bit: "_BIT", + T_varbit: "VARBIT", + T__varbit: "_VARBIT", + T_numeric: "NUMERIC", + T_refcursor: "REFCURSOR", + T__refcursor: "_REFCURSOR", + T_regprocedure: "REGPROCEDURE", + T_regoper: "REGOPER", + T_regoperator: "REGOPERATOR", + T_regclass: "REGCLASS", + T_regtype: "REGTYPE", + T__regprocedure: "_REGPROCEDURE", + T__regoper: "_REGOPER", + T__regoperator: "_REGOPERATOR", + T__regclass: "_REGCLASS", + T__regtype: "_REGTYPE", + T_record: "RECORD", + T_cstring: "CSTRING", + T_any: "ANY", + T_anyarray: "ANYARRAY", + T_void: "VOID", + T_trigger: "TRIGGER", + T_language_handler: "LANGUAGE_HANDLER", + T_internal: "INTERNAL", + T_opaque: "OPAQUE", + T_anyelement: "ANYELEMENT", + T__record: "_RECORD", + T_anynonarray: "ANYNONARRAY", + T_pg_authid: "PG_AUTHID", + T_pg_auth_members: "PG_AUTH_MEMBERS", + T__txid_snapshot: "_TXID_SNAPSHOT", + T_uuid: "UUID", + T__uuid: "_UUID", + T_txid_snapshot: "TXID_SNAPSHOT", + T_fdw_handler: "FDW_HANDLER", + T_pg_lsn: "PG_LSN", + T__pg_lsn: "_PG_LSN", + T_tsm_handler: "TSM_HANDLER", + T_anyenum: "ANYENUM", + T_tsvector: "TSVECTOR", + T_tsquery: "TSQUERY", + T_gtsvector: "GTSVECTOR", + T__tsvector: "_TSVECTOR", + T__gtsvector: "_GTSVECTOR", + T__tsquery: "_TSQUERY", + T_regconfig: "REGCONFIG", + T__regconfig: "_REGCONFIG", + T_regdictionary: "REGDICTIONARY", + T__regdictionary: "_REGDICTIONARY", + T_jsonb: "JSONB", + T__jsonb: "_JSONB", + T_anyrange: "ANYRANGE", + T_event_trigger: "EVENT_TRIGGER", + T_int4range: "INT4RANGE", + T__int4range: "_INT4RANGE", + T_numrange: "NUMRANGE", + T__numrange: "_NUMRANGE", + T_tsrange: "TSRANGE", + T__tsrange: "_TSRANGE", + T_tstzrange: "TSTZRANGE", + T__tstzrange: "_TSTZRANGE", + T_daterange: "DATERANGE", + T__daterange: "_DATERANGE", + T_int8range: "INT8RANGE", + T__int8range: "_INT8RANGE", + T_pg_shseclabel: "PG_SHSECLABEL", + T_regnamespace: "REGNAMESPACE", + T__regnamespace: "_REGNAMESPACE", + T_regrole: "REGROLE", + T__regrole: "_REGROLE", +} diff --git a/vendor/github.com/lib/pq/rows.go b/vendor/github.com/lib/pq/rows.go new file mode 100644 index 000000000..c6aa5b9a3 --- /dev/null +++ b/vendor/github.com/lib/pq/rows.go @@ -0,0 +1,93 @@ +package pq + +import ( + "math" + "reflect" + "time" + + "github.com/lib/pq/oid" +) + +const headerSize = 4 + +type fieldDesc struct { + // The object ID of the data type. + OID oid.Oid + // The data type size (see pg_type.typlen). + // Note that negative values denote variable-width types. + Len int + // The type modifier (see pg_attribute.atttypmod). + // The meaning of the modifier is type-specific. + Mod int +} + +func (fd fieldDesc) Type() reflect.Type { + switch fd.OID { + case oid.T_int8: + return reflect.TypeOf(int64(0)) + case oid.T_int4: + return reflect.TypeOf(int32(0)) + case oid.T_int2: + return reflect.TypeOf(int16(0)) + case oid.T_varchar, oid.T_text: + return reflect.TypeOf("") + case oid.T_bool: + return reflect.TypeOf(false) + case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz: + return reflect.TypeOf(time.Time{}) + case oid.T_bytea: + return reflect.TypeOf([]byte(nil)) + default: + return reflect.TypeOf(new(interface{})).Elem() + } +} + +func (fd fieldDesc) Name() string { + return oid.TypeName[fd.OID] +} + +func (fd fieldDesc) Length() (length int64, ok bool) { + switch fd.OID { + case oid.T_text, oid.T_bytea: + return math.MaxInt64, true + case oid.T_varchar, oid.T_bpchar: + return int64(fd.Mod - headerSize), true + default: + return 0, false + } +} + +func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) { + switch fd.OID { + case oid.T_numeric, oid.T__numeric: + mod := fd.Mod - headerSize + precision = int64((mod >> 16) & 0xffff) + scale = int64(mod & 0xffff) + return precision, scale, true + default: + return 0, 0, false + } +} + +// ColumnTypeScanType returns the value type that can be used to scan types into. +func (rs *rows) ColumnTypeScanType(index int) reflect.Type { + return rs.colTyps[index].Type() +} + +// ColumnTypeDatabaseTypeName return the database system type name. +func (rs *rows) ColumnTypeDatabaseTypeName(index int) string { + return rs.colTyps[index].Name() +} + +// ColumnTypeLength returns 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. +func (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) { + return rs.colTyps[index].Length() +} + +// ColumnTypePrecisionScale should return the precision and scale for decimal +// types. If not applicable, ok should be false. +func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + return rs.colTyps[index].PrecisionScale() +} diff --git a/vendor/github.com/lib/pq/ssl.go b/vendor/github.com/lib/pq/ssl.go new file mode 100644 index 000000000..e1a326a0d --- /dev/null +++ b/vendor/github.com/lib/pq/ssl.go @@ -0,0 +1,169 @@ +package pq + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + "net" + "os" + "os/user" + "path/filepath" +) + +// ssl generates a function to upgrade a net.Conn based on the "sslmode" and +// related settings. The function is nil when no upgrade should take place. +func ssl(o values) (func(net.Conn) (net.Conn, error), error) { + verifyCaOnly := false + tlsConf := tls.Config{} + switch mode := o["sslmode"]; mode { + // "require" is the default. + case "", "require": + // We must skip TLS's own verification since it requires full + // verification since Go 1.3. + tlsConf.InsecureSkipVerify = true + + // From http://www.postgresql.org/docs/current/static/libpq-ssl.html: + // + // Note: For backwards compatibility with earlier versions of + // PostgreSQL, if a root CA file exists, the behavior of + // sslmode=require will be the same as that of verify-ca, meaning the + // server certificate is validated against the CA. Relying on this + // behavior is discouraged, and applications that need certificate + // validation should always use verify-ca or verify-full. + if sslrootcert, ok := o["sslrootcert"]; ok { + if _, err := os.Stat(sslrootcert); err == nil { + verifyCaOnly = true + } else { + delete(o, "sslrootcert") + } + } + case "verify-ca": + // We must skip TLS's own verification since it requires full + // verification since Go 1.3. + tlsConf.InsecureSkipVerify = true + verifyCaOnly = true + case "verify-full": + tlsConf.ServerName = o["host"] + case "disable": + return nil, nil + default: + return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) + } + + err := sslClientCertificates(&tlsConf, o) + if err != nil { + return nil, err + } + err = sslCertificateAuthority(&tlsConf, o) + if err != nil { + return nil, err + } + sslRenegotiation(&tlsConf) + + return func(conn net.Conn) (net.Conn, error) { + client := tls.Client(conn, &tlsConf) + if verifyCaOnly { + err := sslVerifyCertificateAuthority(client, &tlsConf) + if err != nil { + return nil, err + } + } + return client, nil + }, nil +} + +// sslClientCertificates adds the certificate specified in the "sslcert" and +// "sslkey" settings, or if they aren't set, from the .postgresql directory +// in the user's home directory. The configured files must exist and have +// the correct permissions. +func sslClientCertificates(tlsConf *tls.Config, o values) error { + // user.Current() might fail when cross-compiling. We have to ignore the + // error and continue without home directory defaults, since we wouldn't + // know from where to load them. + user, _ := user.Current() + + // In libpq, the client certificate is only loaded if the setting is not blank. + // + // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037 + sslcert := o["sslcert"] + if len(sslcert) == 0 && user != nil { + sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt") + } + // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045 + if len(sslcert) == 0 { + return nil + } + // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054 + if _, err := os.Stat(sslcert); os.IsNotExist(err) { + return nil + } else if err != nil { + return err + } + + // In libpq, the ssl key is only loaded if the setting is not blank. + // + // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222 + sslkey := o["sslkey"] + if len(sslkey) == 0 && user != nil { + sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key") + } + + if len(sslkey) > 0 { + if err := sslKeyPermissions(sslkey); err != nil { + return err + } + } + + cert, err := tls.LoadX509KeyPair(sslcert, sslkey) + if err != nil { + return err + } + + tlsConf.Certificates = []tls.Certificate{cert} + return nil +} + +// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting. +func sslCertificateAuthority(tlsConf *tls.Config, o values) error { + // In libpq, the root certificate is only loaded if the setting is not blank. + // + // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951 + if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 { + tlsConf.RootCAs = x509.NewCertPool() + + cert, err := ioutil.ReadFile(sslrootcert) + if err != nil { + return err + } + + if !tlsConf.RootCAs.AppendCertsFromPEM(cert) { + return fmterrorf("couldn't parse pem in sslrootcert") + } + } + + return nil +} + +// sslVerifyCertificateAuthority carries out a TLS handshake to the server and +// verifies the presented certificate against the CA, i.e. the one specified in +// sslrootcert or the system CA if sslrootcert was not specified. +func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error { + err := client.Handshake() + if err != nil { + return err + } + certs := client.ConnectionState().PeerCertificates + opts := x509.VerifyOptions{ + DNSName: client.ConnectionState().ServerName, + Intermediates: x509.NewCertPool(), + Roots: tlsConf.RootCAs, + } + for i, cert := range certs { + if i == 0 { + continue + } + opts.Intermediates.AddCert(cert) + } + _, err = certs[0].Verify(opts) + return err +} diff --git a/vendor/github.com/lib/pq/ssl_go1.7.go b/vendor/github.com/lib/pq/ssl_go1.7.go new file mode 100644 index 000000000..d7ba43b32 --- /dev/null +++ b/vendor/github.com/lib/pq/ssl_go1.7.go @@ -0,0 +1,14 @@ +// +build go1.7 + +package pq + +import "crypto/tls" + +// Accept renegotiation requests initiated by the backend. +// +// Renegotiation was deprecated then removed from PostgreSQL 9.5, but +// the default configuration of older versions has it enabled. Redshift +// also initiates renegotiations and cannot be reconfigured. +func sslRenegotiation(conf *tls.Config) { + conf.Renegotiation = tls.RenegotiateFreelyAsClient +} diff --git a/vendor/github.com/lib/pq/ssl_permissions.go b/vendor/github.com/lib/pq/ssl_permissions.go new file mode 100644 index 000000000..3b7c3a2a3 --- /dev/null +++ b/vendor/github.com/lib/pq/ssl_permissions.go @@ -0,0 +1,20 @@ +// +build !windows + +package pq + +import "os" + +// sslKeyPermissions checks the permissions on user-supplied ssl key files. +// The key file should have very little access. +// +// libpq does not check key file permissions on Windows. +func sslKeyPermissions(sslkey string) error { + info, err := os.Stat(sslkey) + if err != nil { + return err + } + if info.Mode().Perm()&0077 != 0 { + return ErrSSLKeyHasWorldPermissions + } + return nil +} diff --git a/vendor/github.com/lib/pq/ssl_renegotiation.go b/vendor/github.com/lib/pq/ssl_renegotiation.go new file mode 100644 index 000000000..85ed5e437 --- /dev/null +++ b/vendor/github.com/lib/pq/ssl_renegotiation.go @@ -0,0 +1,8 @@ +// +build !go1.7 + +package pq + +import "crypto/tls" + +// Renegotiation is not supported by crypto/tls until Go 1.7. +func sslRenegotiation(*tls.Config) {} diff --git a/vendor/github.com/lib/pq/ssl_windows.go b/vendor/github.com/lib/pq/ssl_windows.go new file mode 100644 index 000000000..5d2c763ce --- /dev/null +++ b/vendor/github.com/lib/pq/ssl_windows.go @@ -0,0 +1,9 @@ +// +build windows + +package pq + +// sslKeyPermissions checks the permissions on user-supplied ssl key files. +// The key file should have very little access. +// +// libpq does not check key file permissions on Windows. +func sslKeyPermissions(string) error { return nil } diff --git a/vendor/github.com/lib/pq/url.go b/vendor/github.com/lib/pq/url.go new file mode 100644 index 000000000..f4d8a7c20 --- /dev/null +++ b/vendor/github.com/lib/pq/url.go @@ -0,0 +1,76 @@ +package pq + +import ( + "fmt" + "net" + nurl "net/url" + "sort" + "strings" +) + +// ParseURL no longer needs to be used by clients of this library since supplying a URL as a +// connection string to sql.Open() is now supported: +// +// sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") +// +// It remains exported here for backwards-compatibility. +// +// ParseURL converts a url to a connection string for driver.Open. +// Example: +// +// "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" +// +// converts to: +// +// "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" +// +// A minimal example: +// +// "postgres://" +// +// This will be blank, causing driver.Open to use all of the defaults +func ParseURL(url string) (string, error) { + u, err := nurl.Parse(url) + if err != nil { + return "", err + } + + if u.Scheme != "postgres" && u.Scheme != "postgresql" { + return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) + } + + var kvs []string + escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) + accrue := func(k, v string) { + if v != "" { + kvs = append(kvs, k+"="+escaper.Replace(v)) + } + } + + if u.User != nil { + v := u.User.Username() + accrue("user", v) + + v, _ = u.User.Password() + accrue("password", v) + } + + if host, port, err := net.SplitHostPort(u.Host); err != nil { + accrue("host", u.Host) + } else { + accrue("host", host) + accrue("port", port) + } + + if u.Path != "" { + accrue("dbname", u.Path[1:]) + } + + q := u.Query() + for k := range q { + accrue(k, q.Get(k)) + } + + sort.Strings(kvs) // Makes testing easier (not a performance concern) + return strings.Join(kvs, " "), nil +} diff --git a/vendor/github.com/lib/pq/user_posix.go b/vendor/github.com/lib/pq/user_posix.go new file mode 100644 index 000000000..bf982524f --- /dev/null +++ b/vendor/github.com/lib/pq/user_posix.go @@ -0,0 +1,24 @@ +// Package pq is a pure Go Postgres driver for the database/sql package. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris rumprun + +package pq + +import ( + "os" + "os/user" +) + +func userCurrent() (string, error) { + u, err := user.Current() + if err == nil { + return u.Username, nil + } + + name := os.Getenv("USER") + if name != "" { + return name, nil + } + + return "", ErrCouldNotDetectUsername +} diff --git a/vendor/github.com/lib/pq/user_windows.go b/vendor/github.com/lib/pq/user_windows.go new file mode 100644 index 000000000..2b691267b --- /dev/null +++ b/vendor/github.com/lib/pq/user_windows.go @@ -0,0 +1,27 @@ +// Package pq is a pure Go Postgres driver for the database/sql package. +package pq + +import ( + "path/filepath" + "syscall" +) + +// Perform Windows user name lookup identically to libpq. +// +// The PostgreSQL code makes use of the legacy Win32 function +// GetUserName, and that function has not been imported into stock Go. +// GetUserNameEx is available though, the difference being that a +// wider range of names are available. To get the output to be the +// same as GetUserName, only the base (or last) component of the +// result is returned. +func userCurrent() (string, error) { + pw_name := make([]uint16, 128) + pwname_size := uint32(len(pw_name)) - 1 + err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) + if err != nil { + return "", ErrCouldNotDetectUsername + } + s := syscall.UTF16ToString(pw_name) + u := filepath.Base(s) + return u, nil +} diff --git a/vendor/github.com/lib/pq/uuid.go b/vendor/github.com/lib/pq/uuid.go new file mode 100644 index 000000000..9a1b9e074 --- /dev/null +++ b/vendor/github.com/lib/pq/uuid.go @@ -0,0 +1,23 @@ +package pq + +import ( + "encoding/hex" + "fmt" +) + +// decodeUUIDBinary interprets the binary format of a uuid, returning it in text format. +func decodeUUIDBinary(src []byte) ([]byte, error) { + if len(src) != 16 { + return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src)) + } + + dst := make([]byte, 36) + dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-' + hex.Encode(dst[0:], src[0:4]) + hex.Encode(dst[9:], src[4:6]) + hex.Encode(dst[14:], src[6:8]) + hex.Encode(dst[19:], src[8:10]) + hex.Encode(dst[24:], src[10:16]) + + return dst, nil +} diff --git a/vendor/github.com/mitchellh/reflectwalk/location.go b/vendor/github.com/mitchellh/reflectwalk/location.go index 7c59d764c..6a7f17611 100644 --- a/vendor/github.com/mitchellh/reflectwalk/location.go +++ b/vendor/github.com/mitchellh/reflectwalk/location.go @@ -11,6 +11,8 @@ const ( MapValue Slice SliceElem + Array + ArrayElem Struct StructField WalkLoc diff --git a/vendor/github.com/mitchellh/reflectwalk/location_string.go b/vendor/github.com/mitchellh/reflectwalk/location_string.go index d3cfe8545..70760cf4c 100644 --- a/vendor/github.com/mitchellh/reflectwalk/location_string.go +++ b/vendor/github.com/mitchellh/reflectwalk/location_string.go @@ -1,15 +1,15 @@ -// generated by stringer -type=Location location.go; DO NOT EDIT +// Code generated by "stringer -type=Location location.go"; DO NOT EDIT. package reflectwalk import "fmt" -const _Location_name = "NoneMapMapKeyMapValueSliceSliceElemStructStructFieldWalkLoc" +const _Location_name = "NoneMapMapKeyMapValueSliceSliceElemArrayArrayElemStructStructFieldWalkLoc" -var _Location_index = [...]uint8{0, 4, 7, 13, 21, 26, 35, 41, 52, 59} +var _Location_index = [...]uint8{0, 4, 7, 13, 21, 26, 35, 40, 49, 55, 66, 73} func (i Location) String() string { - if i+1 >= Location(len(_Location_index)) { + if i >= Location(len(_Location_index)-1) { return fmt.Sprintf("Location(%d)", i) } return _Location_name[_Location_index[i]:_Location_index[i+1]] diff --git a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go index 1f2066598..d7ab7b6d7 100644 --- a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go +++ b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go @@ -5,6 +5,7 @@ package reflectwalk import ( + "errors" "reflect" ) @@ -18,6 +19,12 @@ type PrimitiveWalker interface { Primitive(reflect.Value) error } +// InterfaceWalker implementations are able to handle interface values as they +// are encountered during the walk. +type InterfaceWalker interface { + Interface(reflect.Value) error +} + // MapWalker implementations are able to handle individual elements // found within a map structure. type MapWalker interface { @@ -32,6 +39,13 @@ type SliceWalker interface { SliceElem(int, reflect.Value) error } +// ArrayWalker implementations are able to handle array elements found +// within complex structures. +type ArrayWalker interface { + Array(reflect.Value) error + ArrayElem(int, reflect.Value) error +} + // StructWalker is an interface that has methods that are called for // structs when a Walk is done. type StructWalker interface { @@ -55,6 +69,14 @@ type PointerWalker interface { PointerExit(bool) error } +// SkipEntry can be returned from walk functions to skip walking +// the value of this field. This is only valid in the following functions: +// +// - Struct: skips all fields from being walked +// - StructField: skips walking the struct value +// +var SkipEntry = errors.New("skip this entry") + // Walk takes an arbitrary value and an interface and traverses the // value, calling callbacks on the interface if they are supported. // The interface should implement one or more of the walker interfaces @@ -79,23 +101,63 @@ func Walk(data, walker interface{}) (err error) { func walk(v reflect.Value, w interface{}) (err error) { // Determine if we're receiving a pointer and if so notify the walker. + // The logic here is convoluted but very important (tests will fail if + // almost any part is changed). I will try to explain here. + // + // First, we check if the value is an interface, if so, we really need + // to check the interface's VALUE to see whether it is a pointer. + // + // Check whether the value is then a pointer. If so, then set pointer + // to true to notify the user. + // + // If we still have a pointer or an interface after the indirections, then + // we unwrap another level + // + // At this time, we also set "v" to be the dereferenced value. This is + // because once we've unwrapped the pointer we want to use that value. pointer := false - if v.Kind() == reflect.Ptr { - pointer = true - v = reflect.Indirect(v) - } - if pw, ok := w.(PointerWalker); ok { - if err = pw.PointerEnter(pointer); err != nil { - return + pointerV := v + + for { + if pointerV.Kind() == reflect.Interface { + if iw, ok := w.(InterfaceWalker); ok { + if err = iw.Interface(pointerV); err != nil { + return + } + } + + pointerV = pointerV.Elem() } - defer func() { - if err != nil { + if pointerV.Kind() == reflect.Ptr { + pointer = true + v = reflect.Indirect(pointerV) + } + if pw, ok := w.(PointerWalker); ok { + if err = pw.PointerEnter(pointer); err != nil { return } - err = pw.PointerExit(pointer) - }() + defer func(pointer bool) { + if err != nil { + return + } + + err = pw.PointerExit(pointer) + }(pointer) + } + + if pointer { + pointerV = v + } + pointer = false + + // If we still have a pointer or interface we have to indirect another level. + switch pointerV.Kind() { + case reflect.Ptr, reflect.Interface: + continue + } + break } // We preserve the original value here because if it is an interface @@ -125,6 +187,9 @@ func walk(v reflect.Value, w interface{}) (err error) { case reflect.Struct: err = walkStruct(v, w) return + case reflect.Array: + err = walkArray(v, w) + return default: panic("unsupported type: " + k.String()) } @@ -232,42 +297,99 @@ func walkSlice(v reflect.Value, w interface{}) (err error) { return nil } +func walkArray(v reflect.Value, w interface{}) (err error) { + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(Array) + } + + if aw, ok := w.(ArrayWalker); ok { + if err := aw.Array(v); err != nil { + return err + } + } + + for i := 0; i < v.Len(); i++ { + elem := v.Index(i) + + if aw, ok := w.(ArrayWalker); ok { + if err := aw.ArrayElem(i, elem); err != nil { + return err + } + } + + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(ArrayElem) + } + + if err := walk(elem, w); err != nil { + return err + } + + if ok { + ew.Exit(ArrayElem) + } + } + + ew, ok = w.(EnterExitWalker) + if ok { + ew.Exit(Array) + } + + return nil +} + func walkStruct(v reflect.Value, w interface{}) (err error) { ew, ewok := w.(EnterExitWalker) if ewok { ew.Enter(Struct) } + skip := false if sw, ok := w.(StructWalker); ok { - if err = sw.Struct(v); err != nil { + err = sw.Struct(v) + if err == SkipEntry { + skip = true + err = nil + } + if err != nil { return } } - vt := v.Type() - for i := 0; i < vt.NumField(); i++ { - sf := vt.Field(i) - f := v.FieldByIndex([]int{i}) + if !skip { + vt := v.Type() + for i := 0; i < vt.NumField(); i++ { + sf := vt.Field(i) + f := v.FieldByIndex([]int{i}) - if sw, ok := w.(StructWalker); ok { - err = sw.StructField(sf, f) + if sw, ok := w.(StructWalker); ok { + err = sw.StructField(sf, f) + + // SkipEntry just pretends this field doesn't even exist + if err == SkipEntry { + continue + } + + if err != nil { + return + } + } + + ew, ok := w.(EnterExitWalker) + if ok { + ew.Enter(StructField) + } + + err = walk(f, w) if err != nil { return } - } - ew, ok := w.(EnterExitWalker) - if ok { - ew.Enter(StructField) - } - - err = walk(f, w) - if err != nil { - return - } - - if ok { - ew.Exit(StructField) + if ok { + ew.Exit(StructField) + } } } diff --git a/vendor/github.com/oklog/run/LICENSE b/vendor/github.com/oklog/run/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/oklog/run/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. diff --git a/vendor/github.com/oklog/run/README.md b/vendor/github.com/oklog/run/README.md new file mode 100644 index 000000000..1b32d8263 --- /dev/null +++ b/vendor/github.com/oklog/run/README.md @@ -0,0 +1,75 @@ +# run + +[![GoDoc](https://godoc.org/github.com/oklog/run?status.svg)](https://godoc.org/github.com/oklog/run) +[![Build Status](https://travis-ci.org/oklog/run.svg?branch=master)](https://travis-ci.org/oklog/run) +[![Go Report Card](https://goreportcard.com/badge/github.com/oklog/run)](https://goreportcard.com/report/github.com/oklog/run) +[![Apache 2 licensed](https://img.shields.io/badge/license-Apache2-blue.svg)](https://raw.githubusercontent.com/oklog/run/master/LICENSE) + +run.Group is a universal mechanism to manage goroutine lifecycles. + +Create a zero-value run.Group, and then add actors to it. Actors are defined as +a pair of functions: an **execute** function, which should run synchronously; +and an **interrupt** function, which, when invoked, should cause the execute +function to return. Finally, invoke Run, which concurrently runs all of the +actors, waits until the first actor exits, invokes the interrupt functions, and +finally returns control to the caller only once all actors have returned. This +general-purpose API allows callers to model pretty much any runnable task, and +achieve well-defined lifecycle semantics for the group. + +run.Group was written to manage component lifecycles in func main for +[OK Log](https://github.com/oklog/oklog). +But it's useful in any circumstance where you need to orchestrate multiple +goroutines as a unit whole. +[Click here](https://www.youtube.com/watch?v=LHe1Cb_Ud_M&t=15m45s) to see a +video of a talk where run.Group is described. + +## Examples + +### context.Context + +```go +ctx, cancel := context.WithCancel(context.Background()) +g.Add(func() error { + return myProcess(ctx, ...) +}, func(error) { + cancel() +}) +``` + +### net.Listener + +```go +ln, _ := net.Listen("tcp", ":8080") +g.Add(func() error { + return http.Serve(ln, nil) +}, func(error) { + ln.Close() +}) +``` + +### io.ReadCloser + +```go +var conn io.ReadCloser = ... +g.Add(func() error { + s := bufio.NewScanner(conn) + for s.Scan() { + println(s.Text()) + } + return s.Err() +}, func(error) { + conn.Close() +}) +``` + +## Comparisons + +Package run is somewhat similar to package +[errgroup](https://godoc.org/golang.org/x/sync/errgroup), +except it doesn't require actor goroutines to understand context semantics. + +It's somewhat similar to package +[tomb.v1](https://godoc.org/gopkg.in/tomb.v1) or +[tomb.v2](https://godoc.org/gopkg.in/tomb.v2), +except it has a much smaller API surface, delegating e.g. staged shutdown of +goroutines to the caller. diff --git a/vendor/github.com/oklog/run/group.go b/vendor/github.com/oklog/run/group.go new file mode 100644 index 000000000..832d47dd1 --- /dev/null +++ b/vendor/github.com/oklog/run/group.go @@ -0,0 +1,62 @@ +// Package run implements an actor-runner with deterministic teardown. It is +// somewhat similar to package errgroup, except it does not require actor +// goroutines to understand context semantics. This makes it suitable for use in +// more circumstances; for example, goroutines which are handling connections +// from net.Listeners, or scanning input from a closable io.Reader. +package run + +// Group collects actors (functions) and runs them concurrently. +// When one actor (function) returns, all actors are interrupted. +// The zero value of a Group is useful. +type Group struct { + actors []actor +} + +// Add an actor (function) to the group. Each actor must be pre-emptable by an +// interrupt function. That is, if interrupt is invoked, execute should return. +// Also, it must be safe to call interrupt even after execute has returned. +// +// The first actor (function) to return interrupts all running actors. +// The error is passed to the interrupt functions, and is returned by Run. +func (g *Group) Add(execute func() error, interrupt func(error)) { + g.actors = append(g.actors, actor{execute, interrupt}) +} + +// Run all actors (functions) concurrently. +// When the first actor returns, all others are interrupted. +// Run only returns when all actors have exited. +// Run returns the error returned by the first exiting actor. +func (g *Group) Run() error { + if len(g.actors) == 0 { + return nil + } + + // Run each actor. + errors := make(chan error, len(g.actors)) + for _, a := range g.actors { + go func(a actor) { + errors <- a.execute() + }(a) + } + + // Wait for the first actor to stop. + err := <-errors + + // Signal all actors to stop. + for _, a := range g.actors { + a.interrupt(err) + } + + // Wait for all actors to stop. + for i := 1; i < cap(errors); i++ { + <-errors + } + + // Return the original error. + return err +} + +type actor struct { + execute func() error + interrupt func(error) +} diff --git a/vendor/github.com/patrickmn/go-cache/CONTRIBUTORS b/vendor/github.com/patrickmn/go-cache/CONTRIBUTORS new file mode 100644 index 000000000..2b16e9974 --- /dev/null +++ b/vendor/github.com/patrickmn/go-cache/CONTRIBUTORS @@ -0,0 +1,9 @@ +This is a list of people who have contributed code to go-cache. They, or their +employers, are the copyright holders of the contributed code. Contributed code +is subject to the license restrictions listed in LICENSE (as they were when the +code was contributed.) + +Dustin Sallings +Jason Mooberry +Sergey Shepelev +Alex Edwards diff --git a/vendor/github.com/patrickmn/go-cache/LICENSE b/vendor/github.com/patrickmn/go-cache/LICENSE new file mode 100644 index 000000000..db9903c75 --- /dev/null +++ b/vendor/github.com/patrickmn/go-cache/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012-2017 Patrick Mylund Nielsen and the go-cache contributors + +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/patrickmn/go-cache/README.md b/vendor/github.com/patrickmn/go-cache/README.md new file mode 100644 index 000000000..c5789cc66 --- /dev/null +++ b/vendor/github.com/patrickmn/go-cache/README.md @@ -0,0 +1,83 @@ +# go-cache + +go-cache is an in-memory key:value store/cache similar to memcached that is +suitable for applications running on a single machine. Its major advantage is +that, being essentially a thread-safe `map[string]interface{}` with expiration +times, it doesn't need to serialize or transmit its contents over the network. + +Any object can be stored, for a given duration or forever, and the cache can be +safely used by multiple goroutines. + +Although go-cache isn't meant to be used as a persistent datastore, the entire +cache can be saved to and loaded from a file (using `c.Items()` to retrieve the +items map to serialize, and `NewFrom()` to create a cache from a deserialized +one) to recover from downtime quickly. (See the docs for `NewFrom()` for caveats.) + +### Installation + +`go get github.com/patrickmn/go-cache` + +### Usage + +```go +import ( + "fmt" + "github.com/patrickmn/go-cache" + "time" +) + +func main() { + // Create a cache with a default expiration time of 5 minutes, and which + // purges expired items every 10 minutes + c := cache.New(5*time.Minute, 10*time.Minute) + + // Set the value of the key "foo" to "bar", with the default expiration time + c.Set("foo", "bar", cache.DefaultExpiration) + + // Set the value of the key "baz" to 42, with no expiration time + // (the item won't be removed until it is re-set, or removed using + // c.Delete("baz") + c.Set("baz", 42, cache.NoExpiration) + + // Get the string associated with the key "foo" from the cache + foo, found := c.Get("foo") + if found { + fmt.Println(foo) + } + + // Since Go is statically typed, and cache values can be anything, type + // assertion is needed when values are being passed to functions that don't + // take arbitrary types, (i.e. interface{}). The simplest way to do this for + // values which will only be used once--e.g. for passing to another + // function--is: + foo, found := c.Get("foo") + if found { + MyFunction(foo.(string)) + } + + // This gets tedious if the value is used several times in the same function. + // You might do either of the following instead: + if x, found := c.Get("foo"); found { + foo := x.(string) + // ... + } + // or + var foo string + if x, found := c.Get("foo"); found { + foo = x.(string) + } + // ... + // foo can then be passed around freely as a string + + // Want performance? Store pointers! + c.Set("foo", &MyStruct, cache.DefaultExpiration) + if x, found := c.Get("foo"); found { + foo := x.(*MyStruct) + // ... + } +} +``` + +### Reference + +`godoc` or [http://godoc.org/github.com/patrickmn/go-cache](http://godoc.org/github.com/patrickmn/go-cache) diff --git a/vendor/github.com/patrickmn/go-cache/cache.go b/vendor/github.com/patrickmn/go-cache/cache.go new file mode 100644 index 000000000..db88d2f2c --- /dev/null +++ b/vendor/github.com/patrickmn/go-cache/cache.go @@ -0,0 +1,1161 @@ +package cache + +import ( + "encoding/gob" + "fmt" + "io" + "os" + "runtime" + "sync" + "time" +) + +type Item struct { + Object interface{} + Expiration int64 +} + +// Returns true if the item has expired. +func (item Item) Expired() bool { + if item.Expiration == 0 { + return false + } + return time.Now().UnixNano() > item.Expiration +} + +const ( + // For use with functions that take an expiration time. + NoExpiration time.Duration = -1 + // For use with functions that take an expiration time. Equivalent to + // passing in the same expiration duration as was given to New() or + // NewFrom() when the cache was created (e.g. 5 minutes.) + DefaultExpiration time.Duration = 0 +) + +type Cache struct { + *cache + // If this is confusing, see the comment at the bottom of New() +} + +type cache struct { + defaultExpiration time.Duration + items map[string]Item + mu sync.RWMutex + onEvicted func(string, interface{}) + janitor *janitor +} + +// Add an item to the cache, replacing any existing item. If the duration is 0 +// (DefaultExpiration), the cache's default expiration time is used. If it is -1 +// (NoExpiration), the item never expires. +func (c *cache) Set(k string, x interface{}, d time.Duration) { + // "Inlining" of set + var e int64 + if d == DefaultExpiration { + d = c.defaultExpiration + } + if d > 0 { + e = time.Now().Add(d).UnixNano() + } + c.mu.Lock() + c.items[k] = Item{ + Object: x, + Expiration: e, + } + // TODO: Calls to mu.Unlock are currently not deferred because defer + // adds ~200 ns (as of go1.) + c.mu.Unlock() +} + +func (c *cache) set(k string, x interface{}, d time.Duration) { + var e int64 + if d == DefaultExpiration { + d = c.defaultExpiration + } + if d > 0 { + e = time.Now().Add(d).UnixNano() + } + c.items[k] = Item{ + Object: x, + Expiration: e, + } +} + +// Add an item to the cache, replacing any existing item, using the default +// expiration. +func (c *cache) SetDefault(k string, x interface{}) { + c.Set(k, x, DefaultExpiration) +} + +// Add an item to the cache only if an item doesn't already exist for the given +// key, or if the existing item has expired. Returns an error otherwise. +func (c *cache) Add(k string, x interface{}, d time.Duration) error { + c.mu.Lock() + _, found := c.get(k) + if found { + c.mu.Unlock() + return fmt.Errorf("Item %s already exists", k) + } + c.set(k, x, d) + c.mu.Unlock() + return nil +} + +// Set a new value for the cache key only if it already exists, and the existing +// item hasn't expired. Returns an error otherwise. +func (c *cache) Replace(k string, x interface{}, d time.Duration) error { + c.mu.Lock() + _, found := c.get(k) + if !found { + c.mu.Unlock() + return fmt.Errorf("Item %s doesn't exist", k) + } + c.set(k, x, d) + c.mu.Unlock() + return nil +} + +// Get an item from the cache. Returns the item or nil, and a bool indicating +// whether the key was found. +func (c *cache) Get(k string) (interface{}, bool) { + c.mu.RLock() + // "Inlining" of get and Expired + item, found := c.items[k] + if !found { + c.mu.RUnlock() + return nil, false + } + if item.Expiration > 0 { + if time.Now().UnixNano() > item.Expiration { + c.mu.RUnlock() + return nil, false + } + } + c.mu.RUnlock() + return item.Object, true +} + +// GetWithExpiration returns an item and its expiration time from the cache. +// It returns the item or nil, the expiration time if one is set (if the item +// never expires a zero value for time.Time is returned), and a bool indicating +// whether the key was found. +func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) { + c.mu.RLock() + // "Inlining" of get and Expired + item, found := c.items[k] + if !found { + c.mu.RUnlock() + return nil, time.Time{}, false + } + + if item.Expiration > 0 { + if time.Now().UnixNano() > item.Expiration { + c.mu.RUnlock() + return nil, time.Time{}, false + } + + // Return the item and the expiration time + c.mu.RUnlock() + return item.Object, time.Unix(0, item.Expiration), true + } + + // If expiration <= 0 (i.e. no expiration time set) then return the item + // and a zeroed time.Time + c.mu.RUnlock() + return item.Object, time.Time{}, true +} + +func (c *cache) get(k string) (interface{}, bool) { + item, found := c.items[k] + if !found { + return nil, false + } + // "Inlining" of Expired + if item.Expiration > 0 { + if time.Now().UnixNano() > item.Expiration { + return nil, false + } + } + return item.Object, true +} + +// Increment an item of type int, int8, int16, int32, int64, uintptr, uint, +// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the +// item's value is not an integer, if it was not found, or if it is not +// possible to increment it by n. To retrieve the incremented value, use one +// of the specialized methods, e.g. IncrementInt64. +func (c *cache) Increment(k string, n int64) error { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return fmt.Errorf("Item %s not found", k) + } + switch v.Object.(type) { + case int: + v.Object = v.Object.(int) + int(n) + case int8: + v.Object = v.Object.(int8) + int8(n) + case int16: + v.Object = v.Object.(int16) + int16(n) + case int32: + v.Object = v.Object.(int32) + int32(n) + case int64: + v.Object = v.Object.(int64) + n + case uint: + v.Object = v.Object.(uint) + uint(n) + case uintptr: + v.Object = v.Object.(uintptr) + uintptr(n) + case uint8: + v.Object = v.Object.(uint8) + uint8(n) + case uint16: + v.Object = v.Object.(uint16) + uint16(n) + case uint32: + v.Object = v.Object.(uint32) + uint32(n) + case uint64: + v.Object = v.Object.(uint64) + uint64(n) + case float32: + v.Object = v.Object.(float32) + float32(n) + case float64: + v.Object = v.Object.(float64) + float64(n) + default: + c.mu.Unlock() + return fmt.Errorf("The value for %s is not an integer", k) + } + c.items[k] = v + c.mu.Unlock() + return nil +} + +// Increment an item of type float32 or float64 by n. Returns an error if the +// item's value is not floating point, if it was not found, or if it is not +// possible to increment it by n. Pass a negative number to decrement the +// value. To retrieve the incremented value, use one of the specialized methods, +// e.g. IncrementFloat64. +func (c *cache) IncrementFloat(k string, n float64) error { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return fmt.Errorf("Item %s not found", k) + } + switch v.Object.(type) { + case float32: + v.Object = v.Object.(float32) + float32(n) + case float64: + v.Object = v.Object.(float64) + n + default: + c.mu.Unlock() + return fmt.Errorf("The value for %s does not have type float32 or float64", k) + } + c.items[k] = v + c.mu.Unlock() + return nil +} + +// Increment an item of type int by n. Returns an error if the item's value is +// not an int, or if it was not found. If there is no error, the incremented +// value is returned. +func (c *cache) IncrementInt(k string, n int) (int, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type int8 by n. Returns an error if the item's value is +// not an int8, or if it was not found. If there is no error, the incremented +// value is returned. +func (c *cache) IncrementInt8(k string, n int8) (int8, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int8) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int8", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type int16 by n. Returns an error if the item's value is +// not an int16, or if it was not found. If there is no error, the incremented +// value is returned. +func (c *cache) IncrementInt16(k string, n int16) (int16, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int16) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int16", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type int32 by n. Returns an error if the item's value is +// not an int32, or if it was not found. If there is no error, the incremented +// value is returned. +func (c *cache) IncrementInt32(k string, n int32) (int32, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int32) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int32", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type int64 by n. Returns an error if the item's value is +// not an int64, or if it was not found. If there is no error, the incremented +// value is returned. +func (c *cache) IncrementInt64(k string, n int64) (int64, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int64) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int64", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type uint by n. Returns an error if the item's value is +// not an uint, or if it was not found. If there is no error, the incremented +// value is returned. +func (c *cache) IncrementUint(k string, n uint) (uint, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type uintptr by n. Returns an error if the item's value +// is not an uintptr, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uintptr) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uintptr", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type uint8 by n. Returns an error if the item's value +// is not an uint8, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint8) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint8", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type uint16 by n. Returns an error if the item's value +// is not an uint16, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint16) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint16", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type uint32 by n. Returns an error if the item's value +// is not an uint32, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint32) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint32", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type uint64 by n. Returns an error if the item's value +// is not an uint64, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint64) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint64", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type float32 by n. Returns an error if the item's value +// is not an float32, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementFloat32(k string, n float32) (float32, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(float32) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an float32", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Increment an item of type float64 by n. Returns an error if the item's value +// is not an float64, or if it was not found. If there is no error, the +// incremented value is returned. +func (c *cache) IncrementFloat64(k string, n float64) (float64, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(float64) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an float64", k) + } + nv := rv + n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type int, int8, int16, int32, int64, uintptr, uint, +// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the +// item's value is not an integer, if it was not found, or if it is not +// possible to decrement it by n. To retrieve the decremented value, use one +// of the specialized methods, e.g. DecrementInt64. +func (c *cache) Decrement(k string, n int64) error { + // TODO: Implement Increment and Decrement more cleanly. + // (Cannot do Increment(k, n*-1) for uints.) + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return fmt.Errorf("Item not found") + } + switch v.Object.(type) { + case int: + v.Object = v.Object.(int) - int(n) + case int8: + v.Object = v.Object.(int8) - int8(n) + case int16: + v.Object = v.Object.(int16) - int16(n) + case int32: + v.Object = v.Object.(int32) - int32(n) + case int64: + v.Object = v.Object.(int64) - n + case uint: + v.Object = v.Object.(uint) - uint(n) + case uintptr: + v.Object = v.Object.(uintptr) - uintptr(n) + case uint8: + v.Object = v.Object.(uint8) - uint8(n) + case uint16: + v.Object = v.Object.(uint16) - uint16(n) + case uint32: + v.Object = v.Object.(uint32) - uint32(n) + case uint64: + v.Object = v.Object.(uint64) - uint64(n) + case float32: + v.Object = v.Object.(float32) - float32(n) + case float64: + v.Object = v.Object.(float64) - float64(n) + default: + c.mu.Unlock() + return fmt.Errorf("The value for %s is not an integer", k) + } + c.items[k] = v + c.mu.Unlock() + return nil +} + +// Decrement an item of type float32 or float64 by n. Returns an error if the +// item's value is not floating point, if it was not found, or if it is not +// possible to decrement it by n. Pass a negative number to decrement the +// value. To retrieve the decremented value, use one of the specialized methods, +// e.g. DecrementFloat64. +func (c *cache) DecrementFloat(k string, n float64) error { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return fmt.Errorf("Item %s not found", k) + } + switch v.Object.(type) { + case float32: + v.Object = v.Object.(float32) - float32(n) + case float64: + v.Object = v.Object.(float64) - n + default: + c.mu.Unlock() + return fmt.Errorf("The value for %s does not have type float32 or float64", k) + } + c.items[k] = v + c.mu.Unlock() + return nil +} + +// Decrement an item of type int by n. Returns an error if the item's value is +// not an int, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementInt(k string, n int) (int, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type int8 by n. Returns an error if the item's value is +// not an int8, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementInt8(k string, n int8) (int8, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int8) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int8", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type int16 by n. Returns an error if the item's value is +// not an int16, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementInt16(k string, n int16) (int16, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int16) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int16", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type int32 by n. Returns an error if the item's value is +// not an int32, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementInt32(k string, n int32) (int32, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int32) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int32", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type int64 by n. Returns an error if the item's value is +// not an int64, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementInt64(k string, n int64) (int64, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(int64) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an int64", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type uint by n. Returns an error if the item's value is +// not an uint, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementUint(k string, n uint) (uint, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type uintptr by n. Returns an error if the item's value +// is not an uintptr, or if it was not found. If there is no error, the +// decremented value is returned. +func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uintptr) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uintptr", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type uint8 by n. Returns an error if the item's value is +// not an uint8, or if it was not found. If there is no error, the decremented +// value is returned. +func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint8) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint8", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type uint16 by n. Returns an error if the item's value +// is not an uint16, or if it was not found. If there is no error, the +// decremented value is returned. +func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint16) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint16", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type uint32 by n. Returns an error if the item's value +// is not an uint32, or if it was not found. If there is no error, the +// decremented value is returned. +func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint32) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint32", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type uint64 by n. Returns an error if the item's value +// is not an uint64, or if it was not found. If there is no error, the +// decremented value is returned. +func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(uint64) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an uint64", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type float32 by n. Returns an error if the item's value +// is not an float32, or if it was not found. If there is no error, the +// decremented value is returned. +func (c *cache) DecrementFloat32(k string, n float32) (float32, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(float32) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an float32", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Decrement an item of type float64 by n. Returns an error if the item's value +// is not an float64, or if it was not found. If there is no error, the +// decremented value is returned. +func (c *cache) DecrementFloat64(k string, n float64) (float64, error) { + c.mu.Lock() + v, found := c.items[k] + if !found || v.Expired() { + c.mu.Unlock() + return 0, fmt.Errorf("Item %s not found", k) + } + rv, ok := v.Object.(float64) + if !ok { + c.mu.Unlock() + return 0, fmt.Errorf("The value for %s is not an float64", k) + } + nv := rv - n + v.Object = nv + c.items[k] = v + c.mu.Unlock() + return nv, nil +} + +// Delete an item from the cache. Does nothing if the key is not in the cache. +func (c *cache) Delete(k string) { + c.mu.Lock() + v, evicted := c.delete(k) + c.mu.Unlock() + if evicted { + c.onEvicted(k, v) + } +} + +func (c *cache) delete(k string) (interface{}, bool) { + if c.onEvicted != nil { + if v, found := c.items[k]; found { + delete(c.items, k) + return v.Object, true + } + } + delete(c.items, k) + return nil, false +} + +type keyAndValue struct { + key string + value interface{} +} + +// Delete all expired items from the cache. +func (c *cache) DeleteExpired() { + var evictedItems []keyAndValue + now := time.Now().UnixNano() + c.mu.Lock() + for k, v := range c.items { + // "Inlining" of expired + if v.Expiration > 0 && now > v.Expiration { + ov, evicted := c.delete(k) + if evicted { + evictedItems = append(evictedItems, keyAndValue{k, ov}) + } + } + } + c.mu.Unlock() + for _, v := range evictedItems { + c.onEvicted(v.key, v.value) + } +} + +// Sets an (optional) function that is called with the key and value when an +// item is evicted from the cache. (Including when it is deleted manually, but +// not when it is overwritten.) Set to nil to disable. +func (c *cache) OnEvicted(f func(string, interface{})) { + c.mu.Lock() + c.onEvicted = f + c.mu.Unlock() +} + +// Write the cache's items (using Gob) to an io.Writer. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *cache) Save(w io.Writer) (err error) { + enc := gob.NewEncoder(w) + defer func() { + if x := recover(); x != nil { + err = fmt.Errorf("Error registering item types with Gob library") + } + }() + c.mu.RLock() + defer c.mu.RUnlock() + for _, v := range c.items { + gob.Register(v.Object) + } + err = enc.Encode(&c.items) + return +} + +// Save the cache's items to the given filename, creating the file if it +// doesn't exist, and overwriting it if it does. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *cache) SaveFile(fname string) error { + fp, err := os.Create(fname) + if err != nil { + return err + } + err = c.Save(fp) + if err != nil { + fp.Close() + return err + } + return fp.Close() +} + +// Add (Gob-serialized) cache items from an io.Reader, excluding any items with +// keys that already exist (and haven't expired) in the current cache. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *cache) Load(r io.Reader) error { + dec := gob.NewDecoder(r) + items := map[string]Item{} + err := dec.Decode(&items) + if err == nil { + c.mu.Lock() + defer c.mu.Unlock() + for k, v := range items { + ov, found := c.items[k] + if !found || ov.Expired() { + c.items[k] = v + } + } + } + return err +} + +// Load and add cache items from the given filename, excluding any items with +// keys that already exist in the current cache. +// +// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the +// documentation for NewFrom().) +func (c *cache) LoadFile(fname string) error { + fp, err := os.Open(fname) + if err != nil { + return err + } + err = c.Load(fp) + if err != nil { + fp.Close() + return err + } + return fp.Close() +} + +// Copies all unexpired items in the cache into a new map and returns it. +func (c *cache) Items() map[string]Item { + c.mu.RLock() + defer c.mu.RUnlock() + m := make(map[string]Item, len(c.items)) + now := time.Now().UnixNano() + for k, v := range c.items { + // "Inlining" of Expired + if v.Expiration > 0 { + if now > v.Expiration { + continue + } + } + m[k] = v + } + return m +} + +// Returns the number of items in the cache. This may include items that have +// expired, but have not yet been cleaned up. +func (c *cache) ItemCount() int { + c.mu.RLock() + n := len(c.items) + c.mu.RUnlock() + return n +} + +// Delete all items from the cache. +func (c *cache) Flush() { + c.mu.Lock() + c.items = map[string]Item{} + c.mu.Unlock() +} + +type janitor struct { + Interval time.Duration + stop chan bool +} + +func (j *janitor) Run(c *cache) { + ticker := time.NewTicker(j.Interval) + for { + select { + case <-ticker.C: + c.DeleteExpired() + case <-j.stop: + ticker.Stop() + return + } + } +} + +func stopJanitor(c *Cache) { + c.janitor.stop <- true +} + +func runJanitor(c *cache, ci time.Duration) { + j := &janitor{ + Interval: ci, + stop: make(chan bool), + } + c.janitor = j + go j.Run(c) +} + +func newCache(de time.Duration, m map[string]Item) *cache { + if de == 0 { + de = -1 + } + c := &cache{ + defaultExpiration: de, + items: m, + } + return c +} + +func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache { + c := newCache(de, m) + // This trick ensures that the janitor goroutine (which--granted it + // was enabled--is running DeleteExpired on c forever) does not keep + // the returned C object from being garbage collected. When it is + // garbage collected, the finalizer stops the janitor goroutine, after + // which c can be collected. + C := &Cache{c} + if ci > 0 { + runJanitor(c, ci) + runtime.SetFinalizer(C, stopJanitor) + } + return C +} + +// Return a new cache with a given default expiration duration and cleanup +// interval. If the expiration duration is less than one (or NoExpiration), +// the items in the cache never expire (by default), and must be deleted +// manually. If the cleanup interval is less than one, expired items are not +// deleted from the cache before calling c.DeleteExpired(). +func New(defaultExpiration, cleanupInterval time.Duration) *Cache { + items := make(map[string]Item) + return newCacheWithJanitor(defaultExpiration, cleanupInterval, items) +} + +// Return a new cache with a given default expiration duration and cleanup +// interval. If the expiration duration is less than one (or NoExpiration), +// the items in the cache never expire (by default), and must be deleted +// manually. If the cleanup interval is less than one, expired items are not +// deleted from the cache before calling c.DeleteExpired(). +// +// NewFrom() also accepts an items map which will serve as the underlying map +// for the cache. This is useful for starting from a deserialized cache +// (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g. +// make(map[string]Item, 500) to improve startup performance when the cache +// is expected to reach a certain minimum size. +// +// Only the cache's methods synchronize access to this map, so it is not +// recommended to keep any references to the map around after creating a cache. +// If need be, the map can be accessed at a later point using c.Items() (subject +// to the same caveat.) +// +// Note regarding serialization: When using e.g. gob, make sure to +// gob.Register() the individual types stored in the cache before encoding a +// map retrieved with c.Items(), and to register those same types before +// decoding a blob containing an items map. +func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache { + return newCacheWithJanitor(defaultExpiration, cleanupInterval, items) +} diff --git a/vendor/github.com/patrickmn/go-cache/sharded.go b/vendor/github.com/patrickmn/go-cache/sharded.go new file mode 100644 index 000000000..bcc0538bc --- /dev/null +++ b/vendor/github.com/patrickmn/go-cache/sharded.go @@ -0,0 +1,192 @@ +package cache + +import ( + "crypto/rand" + "math" + "math/big" + insecurerand "math/rand" + "os" + "runtime" + "time" +) + +// This is an experimental and unexported (for now) attempt at making a cache +// with better algorithmic complexity than the standard one, namely by +// preventing write locks of the entire cache when an item is added. As of the +// time of writing, the overhead of selecting buckets results in cache +// operations being about twice as slow as for the standard cache with small +// total cache sizes, and faster for larger ones. +// +// See cache_test.go for a few benchmarks. + +type unexportedShardedCache struct { + *shardedCache +} + +type shardedCache struct { + seed uint32 + m uint32 + cs []*cache + janitor *shardedJanitor +} + +// djb2 with better shuffling. 5x faster than FNV with the hash.Hash overhead. +func djb33(seed uint32, k string) uint32 { + var ( + l = uint32(len(k)) + d = 5381 + seed + l + i = uint32(0) + ) + // Why is all this 5x faster than a for loop? + if l >= 4 { + for i < l-4 { + d = (d * 33) ^ uint32(k[i]) + d = (d * 33) ^ uint32(k[i+1]) + d = (d * 33) ^ uint32(k[i+2]) + d = (d * 33) ^ uint32(k[i+3]) + i += 4 + } + } + switch l - i { + case 1: + case 2: + d = (d * 33) ^ uint32(k[i]) + case 3: + d = (d * 33) ^ uint32(k[i]) + d = (d * 33) ^ uint32(k[i+1]) + case 4: + d = (d * 33) ^ uint32(k[i]) + d = (d * 33) ^ uint32(k[i+1]) + d = (d * 33) ^ uint32(k[i+2]) + } + return d ^ (d >> 16) +} + +func (sc *shardedCache) bucket(k string) *cache { + return sc.cs[djb33(sc.seed, k)%sc.m] +} + +func (sc *shardedCache) Set(k string, x interface{}, d time.Duration) { + sc.bucket(k).Set(k, x, d) +} + +func (sc *shardedCache) Add(k string, x interface{}, d time.Duration) error { + return sc.bucket(k).Add(k, x, d) +} + +func (sc *shardedCache) Replace(k string, x interface{}, d time.Duration) error { + return sc.bucket(k).Replace(k, x, d) +} + +func (sc *shardedCache) Get(k string) (interface{}, bool) { + return sc.bucket(k).Get(k) +} + +func (sc *shardedCache) Increment(k string, n int64) error { + return sc.bucket(k).Increment(k, n) +} + +func (sc *shardedCache) IncrementFloat(k string, n float64) error { + return sc.bucket(k).IncrementFloat(k, n) +} + +func (sc *shardedCache) Decrement(k string, n int64) error { + return sc.bucket(k).Decrement(k, n) +} + +func (sc *shardedCache) Delete(k string) { + sc.bucket(k).Delete(k) +} + +func (sc *shardedCache) DeleteExpired() { + for _, v := range sc.cs { + v.DeleteExpired() + } +} + +// Returns the items in the cache. This may include items that have expired, +// but have not yet been cleaned up. If this is significant, the Expiration +// fields of the items should be checked. Note that explicit synchronization +// is needed to use a cache and its corresponding Items() return values at +// the same time, as the maps are shared. +func (sc *shardedCache) Items() []map[string]Item { + res := make([]map[string]Item, len(sc.cs)) + for i, v := range sc.cs { + res[i] = v.Items() + } + return res +} + +func (sc *shardedCache) Flush() { + for _, v := range sc.cs { + v.Flush() + } +} + +type shardedJanitor struct { + Interval time.Duration + stop chan bool +} + +func (j *shardedJanitor) Run(sc *shardedCache) { + j.stop = make(chan bool) + tick := time.Tick(j.Interval) + for { + select { + case <-tick: + sc.DeleteExpired() + case <-j.stop: + return + } + } +} + +func stopShardedJanitor(sc *unexportedShardedCache) { + sc.janitor.stop <- true +} + +func runShardedJanitor(sc *shardedCache, ci time.Duration) { + j := &shardedJanitor{ + Interval: ci, + } + sc.janitor = j + go j.Run(sc) +} + +func newShardedCache(n int, de time.Duration) *shardedCache { + max := big.NewInt(0).SetUint64(uint64(math.MaxUint32)) + rnd, err := rand.Int(rand.Reader, max) + var seed uint32 + if err != nil { + os.Stderr.Write([]byte("WARNING: go-cache's newShardedCache failed to read from the system CSPRNG (/dev/urandom or equivalent.) Your system's security may be compromised. Continuing with an insecure seed.\n")) + seed = insecurerand.Uint32() + } else { + seed = uint32(rnd.Uint64()) + } + sc := &shardedCache{ + seed: seed, + m: uint32(n), + cs: make([]*cache, n), + } + for i := 0; i < n; i++ { + c := &cache{ + defaultExpiration: de, + items: map[string]Item{}, + } + sc.cs[i] = c + } + return sc +} + +func unexportedNewSharded(defaultExpiration, cleanupInterval time.Duration, shards int) *unexportedShardedCache { + if defaultExpiration == 0 { + defaultExpiration = -1 + } + sc := newShardedCache(shards, defaultExpiration) + SC := &unexportedShardedCache{sc} + if cleanupInterval > 0 { + runShardedJanitor(sc, cleanupInterval) + runtime.SetFinalizer(SC, stopShardedJanitor) + } + return SC +} diff --git a/vendor/github.com/ryanuber/go-glob/LICENSE b/vendor/github.com/ryanuber/go-glob/LICENSE new file mode 100644 index 000000000..bdfbd9514 --- /dev/null +++ b/vendor/github.com/ryanuber/go-glob/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ryan Uber + +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/ryanuber/go-glob/README.md b/vendor/github.com/ryanuber/go-glob/README.md new file mode 100644 index 000000000..48f7fcb05 --- /dev/null +++ b/vendor/github.com/ryanuber/go-glob/README.md @@ -0,0 +1,29 @@ +# String globbing in golang [![Build Status](https://travis-ci.org/ryanuber/go-glob.svg)](https://travis-ci.org/ryanuber/go-glob) + +`go-glob` is a single-function library implementing basic string glob support. + +Globs are an extremely user-friendly way of supporting string matching without +requiring knowledge of regular expressions or Go's particular regex engine. Most +people understand that if you put a `*` character somewhere in a string, it is +treated as a wildcard. Surprisingly, this functionality isn't found in Go's +standard library, except for `path.Match`, which is intended to be used while +comparing paths (not arbitrary strings), and contains specialized logic for this +use case. A better solution might be a POSIX basic (non-ERE) regular expression +engine for Go, which doesn't exist currently. + +Example +======= + +``` +package main + +import "github.com/ryanuber/go-glob" + +func main() { + glob.Glob("*World!", "Hello, World!") // true + glob.Glob("Hello,*", "Hello, World!") // true + glob.Glob("*ello,*", "Hello, World!") // true + glob.Glob("World!", "Hello, World!") // false + glob.Glob("/home/*", "/home/ryanuber/.bashrc") // true +} +``` diff --git a/vendor/github.com/ryanuber/go-glob/glob.go b/vendor/github.com/ryanuber/go-glob/glob.go new file mode 100644 index 000000000..e67db3be1 --- /dev/null +++ b/vendor/github.com/ryanuber/go-glob/glob.go @@ -0,0 +1,56 @@ +package glob + +import "strings" + +// The character which is treated like a glob +const GLOB = "*" + +// Glob will test a string pattern, potentially containing globs, against a +// subject string. The result is a simple true/false, determining whether or +// not the glob pattern matched the subject text. +func Glob(pattern, subj string) bool { + // Empty pattern can only match empty subject + if pattern == "" { + return subj == pattern + } + + // If the pattern _is_ a glob, it matches everything + if pattern == GLOB { + return true + } + + parts := strings.Split(pattern, GLOB) + + if len(parts) == 1 { + // No globs in pattern, so test for equality + return subj == pattern + } + + leadingGlob := strings.HasPrefix(pattern, GLOB) + trailingGlob := strings.HasSuffix(pattern, GLOB) + end := len(parts) - 1 + + // Go over the leading parts and ensure they match. + for i := 0; i < end; i++ { + idx := strings.Index(subj, parts[i]) + + switch i { + case 0: + // Check the first section. Requires special handling. + if !leadingGlob && idx != 0 { + return false + } + default: + // Check that the middle parts match. + if idx < 0 { + return false + } + } + + // Trim evaluated text from subj as we loop over the pattern. + subj = subj[idx+len(parts[i]):] + } + + // Reached the last section. Requires special handling. + return trailingGlob || strings.HasSuffix(subj, parts[end]) +} diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go new file mode 100644 index 000000000..e28f49d12 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go @@ -0,0 +1,91 @@ +// 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. + +// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539. +package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305" + +import ( + "crypto/cipher" + "encoding/binary" + "errors" +) + +const ( + // KeySize is the size of the key used by this AEAD, in bytes. + KeySize = 32 + // NonceSize is the size of the nonce used with this AEAD, in bytes. + NonceSize = 12 +) + +type chacha20poly1305 struct { + key [8]uint32 +} + +// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key. +func New(key []byte) (cipher.AEAD, error) { + if len(key) != KeySize { + return nil, errors.New("chacha20poly1305: bad key length") + } + ret := new(chacha20poly1305) + ret.key[0] = binary.LittleEndian.Uint32(key[0:4]) + ret.key[1] = binary.LittleEndian.Uint32(key[4:8]) + ret.key[2] = binary.LittleEndian.Uint32(key[8:12]) + ret.key[3] = binary.LittleEndian.Uint32(key[12:16]) + ret.key[4] = binary.LittleEndian.Uint32(key[16:20]) + ret.key[5] = binary.LittleEndian.Uint32(key[20:24]) + ret.key[6] = binary.LittleEndian.Uint32(key[24:28]) + ret.key[7] = binary.LittleEndian.Uint32(key[28:32]) + return ret, nil +} + +func (c *chacha20poly1305) NonceSize() int { + return NonceSize +} + +func (c *chacha20poly1305) Overhead() int { + return 16 +} + +func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if len(nonce) != NonceSize { + panic("chacha20poly1305: bad nonce length passed to Seal") + } + + if uint64(len(plaintext)) > (1<<38)-64 { + panic("chacha20poly1305: plaintext too large") + } + + return c.seal(dst, nonce, plaintext, additionalData) +} + +var errOpen = errors.New("chacha20poly1305: message authentication failed") + +func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if len(nonce) != NonceSize { + panic("chacha20poly1305: bad nonce length passed to Open") + } + if len(ciphertext) < 16 { + return nil, errOpen + } + if uint64(len(ciphertext)) > (1<<38)-48 { + panic("chacha20poly1305: ciphertext too large") + } + + return c.open(dst, nonce, ciphertext, additionalData) +} + +// sliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go new file mode 100644 index 000000000..ec13d1388 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go @@ -0,0 +1,87 @@ +// 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 go1.7,amd64,!gccgo,!appengine + +package chacha20poly1305 + +import ( + "encoding/binary" + + "golang.org/x/crypto/internal/subtle" + "golang.org/x/sys/cpu" +) + +//go:noescape +func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool + +//go:noescape +func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte) + +var ( + useASM = cpu.X86.HasSSSE3 + useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2 +) + +// setupState writes a ChaCha20 input matrix to state. See +// https://tools.ietf.org/html/rfc7539#section-2.3. +func setupState(state *[16]uint32, key *[8]uint32, nonce []byte) { + state[0] = 0x61707865 + state[1] = 0x3320646e + state[2] = 0x79622d32 + state[3] = 0x6b206574 + + state[4] = key[0] + state[5] = key[1] + state[6] = key[2] + state[7] = key[3] + state[8] = key[4] + state[9] = key[5] + state[10] = key[6] + state[11] = key[7] + + state[12] = 0 + state[13] = binary.LittleEndian.Uint32(nonce[:4]) + state[14] = binary.LittleEndian.Uint32(nonce[4:8]) + state[15] = binary.LittleEndian.Uint32(nonce[8:12]) +} + +func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte { + if !useASM { + return c.sealGeneric(dst, nonce, plaintext, additionalData) + } + + var state [16]uint32 + setupState(&state, &c.key, nonce) + + ret, out := sliceForAppend(dst, len(plaintext)+16) + if subtle.InexactOverlap(out, plaintext) { + panic("chacha20poly1305: invalid buffer overlap") + } + chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData) + return ret +} + +func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if !useASM { + return c.openGeneric(dst, nonce, ciphertext, additionalData) + } + + var state [16]uint32 + setupState(&state, &c.key, nonce) + + ciphertext = ciphertext[:len(ciphertext)-16] + ret, out := sliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { + panic("chacha20poly1305: invalid buffer overlap") + } + if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) { + for i := range out { + out[i] = 0 + } + return nil, errOpen + } + + return ret, nil +} diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s new file mode 100644 index 000000000..af76bbcc9 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s @@ -0,0 +1,2695 @@ +// 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. + +// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare. + +// +build go1.7,amd64,!gccgo,!appengine + +#include "textflag.h" +// General register allocation +#define oup DI +#define inp SI +#define inl BX +#define adp CX // free to reuse, after we hash the additional data +#define keyp R8 // free to reuse, when we copy the key to stack +#define itr2 R9 // general iterator +#define itr1 CX // general iterator +#define acc0 R10 +#define acc1 R11 +#define acc2 R12 +#define t0 R13 +#define t1 R14 +#define t2 R15 +#define t3 R8 +// Register and stack allocation for the SSE code +#define rStore (0*16)(BP) +#define sStore (1*16)(BP) +#define state1Store (2*16)(BP) +#define state2Store (3*16)(BP) +#define tmpStore (4*16)(BP) +#define ctr0Store (5*16)(BP) +#define ctr1Store (6*16)(BP) +#define ctr2Store (7*16)(BP) +#define ctr3Store (8*16)(BP) +#define A0 X0 +#define A1 X1 +#define A2 X2 +#define B0 X3 +#define B1 X4 +#define B2 X5 +#define C0 X6 +#define C1 X7 +#define C2 X8 +#define D0 X9 +#define D1 X10 +#define D2 X11 +#define T0 X12 +#define T1 X13 +#define T2 X14 +#define T3 X15 +#define A3 T0 +#define B3 T1 +#define C3 T2 +#define D3 T3 +// Register and stack allocation for the AVX2 code +#define rsStoreAVX2 (0*32)(BP) +#define state1StoreAVX2 (1*32)(BP) +#define state2StoreAVX2 (2*32)(BP) +#define ctr0StoreAVX2 (3*32)(BP) +#define ctr1StoreAVX2 (4*32)(BP) +#define ctr2StoreAVX2 (5*32)(BP) +#define ctr3StoreAVX2 (6*32)(BP) +#define tmpStoreAVX2 (7*32)(BP) // 256 bytes on stack +#define AA0 Y0 +#define AA1 Y5 +#define AA2 Y6 +#define AA3 Y7 +#define BB0 Y14 +#define BB1 Y9 +#define BB2 Y10 +#define BB3 Y11 +#define CC0 Y12 +#define CC1 Y13 +#define CC2 Y8 +#define CC3 Y15 +#define DD0 Y4 +#define DD1 Y1 +#define DD2 Y2 +#define DD3 Y3 +#define TT0 DD3 +#define TT1 AA3 +#define TT2 BB3 +#define TT3 CC3 +// ChaCha20 constants +DATA ·chacha20Constants<>+0x00(SB)/4, $0x61707865 +DATA ·chacha20Constants<>+0x04(SB)/4, $0x3320646e +DATA ·chacha20Constants<>+0x08(SB)/4, $0x79622d32 +DATA ·chacha20Constants<>+0x0c(SB)/4, $0x6b206574 +DATA ·chacha20Constants<>+0x10(SB)/4, $0x61707865 +DATA ·chacha20Constants<>+0x14(SB)/4, $0x3320646e +DATA ·chacha20Constants<>+0x18(SB)/4, $0x79622d32 +DATA ·chacha20Constants<>+0x1c(SB)/4, $0x6b206574 +// <<< 16 with PSHUFB +DATA ·rol16<>+0x00(SB)/8, $0x0504070601000302 +DATA ·rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A +DATA ·rol16<>+0x10(SB)/8, $0x0504070601000302 +DATA ·rol16<>+0x18(SB)/8, $0x0D0C0F0E09080B0A +// <<< 8 with PSHUFB +DATA ·rol8<>+0x00(SB)/8, $0x0605040702010003 +DATA ·rol8<>+0x08(SB)/8, $0x0E0D0C0F0A09080B +DATA ·rol8<>+0x10(SB)/8, $0x0605040702010003 +DATA ·rol8<>+0x18(SB)/8, $0x0E0D0C0F0A09080B + +DATA ·avx2InitMask<>+0x00(SB)/8, $0x0 +DATA ·avx2InitMask<>+0x08(SB)/8, $0x0 +DATA ·avx2InitMask<>+0x10(SB)/8, $0x1 +DATA ·avx2InitMask<>+0x18(SB)/8, $0x0 + +DATA ·avx2IncMask<>+0x00(SB)/8, $0x2 +DATA ·avx2IncMask<>+0x08(SB)/8, $0x0 +DATA ·avx2IncMask<>+0x10(SB)/8, $0x2 +DATA ·avx2IncMask<>+0x18(SB)/8, $0x0 +// Poly1305 key clamp +DATA ·polyClampMask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF +DATA ·polyClampMask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC +DATA ·polyClampMask<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF +DATA ·polyClampMask<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF + +DATA ·sseIncMask<>+0x00(SB)/8, $0x1 +DATA ·sseIncMask<>+0x08(SB)/8, $0x0 +// To load/store the last < 16 bytes in a buffer +DATA ·andMask<>+0x00(SB)/8, $0x00000000000000ff +DATA ·andMask<>+0x08(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x10(SB)/8, $0x000000000000ffff +DATA ·andMask<>+0x18(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x20(SB)/8, $0x0000000000ffffff +DATA ·andMask<>+0x28(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x30(SB)/8, $0x00000000ffffffff +DATA ·andMask<>+0x38(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x40(SB)/8, $0x000000ffffffffff +DATA ·andMask<>+0x48(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x50(SB)/8, $0x0000ffffffffffff +DATA ·andMask<>+0x58(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x60(SB)/8, $0x00ffffffffffffff +DATA ·andMask<>+0x68(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x70(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0x78(SB)/8, $0x0000000000000000 +DATA ·andMask<>+0x80(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0x88(SB)/8, $0x00000000000000ff +DATA ·andMask<>+0x90(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0x98(SB)/8, $0x000000000000ffff +DATA ·andMask<>+0xa0(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0xa8(SB)/8, $0x0000000000ffffff +DATA ·andMask<>+0xb0(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0xb8(SB)/8, $0x00000000ffffffff +DATA ·andMask<>+0xc0(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0xc8(SB)/8, $0x000000ffffffffff +DATA ·andMask<>+0xd0(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0xd8(SB)/8, $0x0000ffffffffffff +DATA ·andMask<>+0xe0(SB)/8, $0xffffffffffffffff +DATA ·andMask<>+0xe8(SB)/8, $0x00ffffffffffffff + +GLOBL ·chacha20Constants<>(SB), (NOPTR+RODATA), $32 +GLOBL ·rol16<>(SB), (NOPTR+RODATA), $32 +GLOBL ·rol8<>(SB), (NOPTR+RODATA), $32 +GLOBL ·sseIncMask<>(SB), (NOPTR+RODATA), $16 +GLOBL ·avx2IncMask<>(SB), (NOPTR+RODATA), $32 +GLOBL ·avx2InitMask<>(SB), (NOPTR+RODATA), $32 +GLOBL ·polyClampMask<>(SB), (NOPTR+RODATA), $32 +GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240 +// No PALIGNR in Go ASM yet (but VPALIGNR is present). +#define shiftB0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X3, X3 +#define shiftB1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x04 // PALIGNR $4, X4, X4 +#define shiftB2Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X5, X5 +#define shiftB3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X13, X13 +#define shiftC0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X6, X6 +#define shiftC1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x08 // PALIGNR $8, X7, X7 +#define shiftC2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc0; BYTE $0x08 // PALIGNR $8, X8, X8 +#define shiftC3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X14, X14 +#define shiftD0Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x0c // PALIGNR $12, X9, X9 +#define shiftD1Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x0c // PALIGNR $12, X10, X10 +#define shiftD2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X11, X11 +#define shiftD3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x0c // PALIGNR $12, X15, X15 +#define shiftB0Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X3, X3 +#define shiftB1Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x0c // PALIGNR $12, X4, X4 +#define shiftB2Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X5, X5 +#define shiftB3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X13, X13 +#define shiftC0Right shiftC0Left +#define shiftC1Right shiftC1Left +#define shiftC2Right shiftC2Left +#define shiftC3Right shiftC3Left +#define shiftD0Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x04 // PALIGNR $4, X9, X9 +#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10 +#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11 +#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15 +// Some macros +#define chachaQR(A, B, C, D, T) \ + PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D \ + PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \ + PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D \ + PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B + +#define chachaQR_AVX2(A, B, C, D, T) \ + VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol16<>(SB), D, D \ + VPADDD D, C, C; VPXOR C, B, B; VPSLLD $12, B, T; VPSRLD $20, B, B; VPXOR T, B, B \ + VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol8<>(SB), D, D \ + VPADDD D, C, C; VPXOR C, B, B; VPSLLD $7, B, T; VPSRLD $25, B, B; VPXOR T, B, B + +#define polyAdd(S) ADDQ S, acc0; ADCQ 8+S, acc1; ADCQ $1, acc2 +#define polyMulStage1 MOVQ (0*8)(BP), AX; MOVQ AX, t2; MULQ acc0; MOVQ AX, t0; MOVQ DX, t1; MOVQ (0*8)(BP), AX; MULQ acc1; IMULQ acc2, t2; ADDQ AX, t1; ADCQ DX, t2 +#define polyMulStage2 MOVQ (1*8)(BP), AX; MOVQ AX, t3; MULQ acc0; ADDQ AX, t1; ADCQ $0, DX; MOVQ DX, acc0; MOVQ (1*8)(BP), AX; MULQ acc1; ADDQ AX, t2; ADCQ $0, DX +#define polyMulStage3 IMULQ acc2, t3; ADDQ acc0, t2; ADCQ DX, t3 +#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t2:t3; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2 + +#define polyMulStage1_AVX2 MOVQ (0*8)(BP), DX; MOVQ DX, t2; MULXQ acc0, t0, t1; IMULQ acc2, t2; MULXQ acc1, AX, DX; ADDQ AX, t1; ADCQ DX, t2 +#define polyMulStage2_AVX2 MOVQ (1*8)(BP), DX; MULXQ acc0, acc0, AX; ADDQ acc0, t1; MULXQ acc1, acc1, t3; ADCQ acc1, t2; ADCQ $0, t3 +#define polyMulStage3_AVX2 IMULQ acc2, DX; ADDQ AX, t2; ADCQ DX, t3 + +#define polyMul polyMulStage1; polyMulStage2; polyMulStage3; polyMulReduceStage +#define polyMulAVX2 polyMulStage1_AVX2; polyMulStage2_AVX2; polyMulStage3_AVX2; polyMulReduceStage +// ---------------------------------------------------------------------------- +TEXT polyHashADInternal<>(SB), NOSPLIT, $0 + // adp points to beginning of additional data + // itr2 holds ad length + XORQ acc0, acc0 + XORQ acc1, acc1 + XORQ acc2, acc2 + CMPQ itr2, $13 + JNE hashADLoop + +openFastTLSAD: + // Special treatment for the TLS case of 13 bytes + MOVQ (adp), acc0 + MOVQ 5(adp), acc1 + SHRQ $24, acc1 + MOVQ $1, acc2 + polyMul + RET + +hashADLoop: + // Hash in 16 byte chunks + CMPQ itr2, $16 + JB hashADTail + polyAdd(0(adp)) + LEAQ (1*16)(adp), adp + SUBQ $16, itr2 + polyMul + JMP hashADLoop + +hashADTail: + CMPQ itr2, $0 + JE hashADDone + + // Hash last < 16 byte tail + XORQ t0, t0 + XORQ t1, t1 + XORQ t2, t2 + ADDQ itr2, adp + +hashADTailLoop: + SHLQ $8, t1:t0 + SHLQ $8, t0 + MOVB -1(adp), t2 + XORQ t2, t0 + DECQ adp + DECQ itr2 + JNE hashADTailLoop + +hashADTailFinish: + ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 + polyMul + + // Finished AD +hashADDone: + RET + +// ---------------------------------------------------------------------------- +// func chacha20Poly1305Open(dst, key, src, ad []byte) bool +TEXT ·chacha20Poly1305Open(SB), 0, $288-97 + // For aligned stack access + MOVQ SP, BP + ADDQ $32, BP + ANDQ $-32, BP + MOVQ dst+0(FP), oup + MOVQ key+24(FP), keyp + MOVQ src+48(FP), inp + MOVQ src_len+56(FP), inl + MOVQ ad+72(FP), adp + + // Check for AVX2 support + CMPB ·useAVX2(SB), $1 + JE chacha20Poly1305Open_AVX2 + + // Special optimization, for very short buffers + CMPQ inl, $128 + JBE openSSE128 // About 16% faster + + // For long buffers, prepare the poly key first + MOVOU ·chacha20Constants<>(SB), A0 + MOVOU (1*16)(keyp), B0 + MOVOU (2*16)(keyp), C0 + MOVOU (3*16)(keyp), D0 + MOVO D0, T1 + + // Store state on stack for future use + MOVO B0, state1Store + MOVO C0, state2Store + MOVO D0, ctr3Store + MOVQ $10, itr2 + +openSSEPreparePolyKey: + chachaQR(A0, B0, C0, D0, T0) + shiftB0Left; shiftC0Left; shiftD0Left + chachaQR(A0, B0, C0, D0, T0) + shiftB0Right; shiftC0Right; shiftD0Right + DECQ itr2 + JNE openSSEPreparePolyKey + + // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded + PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0 + + // Clamp and store the key + PAND ·polyClampMask<>(SB), A0 + MOVO A0, rStore; MOVO B0, sStore + + // Hash AAD + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + +openSSEMainLoop: + CMPQ inl, $256 + JB openSSEMainLoopDone + + // Load state, increment counter blocks + MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0 + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 + MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + + // Store counters + MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store + + // There are 10 ChaCha20 iterations of 2QR each, so for 6 iterations we hash 2 blocks, and for the remaining 4 only 1 block - for a total of 16 + MOVQ $4, itr1 + MOVQ inp, itr2 + +openSSEInternalLoop: + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + polyAdd(0(itr2)) + shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left + shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left + shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left + polyMulStage1 + polyMulStage2 + LEAQ (2*8)(itr2), itr2 + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + polyMulStage3 + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + polyMulReduceStage + shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right + shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right + shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right + DECQ itr1 + JGE openSSEInternalLoop + + polyAdd(0(itr2)) + polyMul + LEAQ (2*8)(itr2), itr2 + + CMPQ itr1, $-6 + JG openSSEInternalLoop + + // Add in the state + PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 + PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 + PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 + PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 + + // Load - xor - store + MOVO D3, tmpStore + MOVOU (0*16)(inp), D3; PXOR D3, A0; MOVOU A0, (0*16)(oup) + MOVOU (1*16)(inp), D3; PXOR D3, B0; MOVOU B0, (1*16)(oup) + MOVOU (2*16)(inp), D3; PXOR D3, C0; MOVOU C0, (2*16)(oup) + MOVOU (3*16)(inp), D3; PXOR D3, D0; MOVOU D0, (3*16)(oup) + MOVOU (4*16)(inp), D0; PXOR D0, A1; MOVOU A1, (4*16)(oup) + MOVOU (5*16)(inp), D0; PXOR D0, B1; MOVOU B1, (5*16)(oup) + MOVOU (6*16)(inp), D0; PXOR D0, C1; MOVOU C1, (6*16)(oup) + MOVOU (7*16)(inp), D0; PXOR D0, D1; MOVOU D1, (7*16)(oup) + MOVOU (8*16)(inp), D0; PXOR D0, A2; MOVOU A2, (8*16)(oup) + MOVOU (9*16)(inp), D0; PXOR D0, B2; MOVOU B2, (9*16)(oup) + MOVOU (10*16)(inp), D0; PXOR D0, C2; MOVOU C2, (10*16)(oup) + MOVOU (11*16)(inp), D0; PXOR D0, D2; MOVOU D2, (11*16)(oup) + MOVOU (12*16)(inp), D0; PXOR D0, A3; MOVOU A3, (12*16)(oup) + MOVOU (13*16)(inp), D0; PXOR D0, B3; MOVOU B3, (13*16)(oup) + MOVOU (14*16)(inp), D0; PXOR D0, C3; MOVOU C3, (14*16)(oup) + MOVOU (15*16)(inp), D0; PXOR tmpStore, D0; MOVOU D0, (15*16)(oup) + LEAQ 256(inp), inp + LEAQ 256(oup), oup + SUBQ $256, inl + JMP openSSEMainLoop + +openSSEMainLoopDone: + // Handle the various tail sizes efficiently + TESTQ inl, inl + JE openSSEFinalize + CMPQ inl, $64 + JBE openSSETail64 + CMPQ inl, $128 + JBE openSSETail128 + CMPQ inl, $192 + JBE openSSETail192 + JMP openSSETail256 + +openSSEFinalize: + // Hash in the PT, AAD lengths + ADDQ ad_len+80(FP), acc0; ADCQ src_len+56(FP), acc1; ADCQ $1, acc2 + polyMul + + // Final reduce + MOVQ acc0, t0 + MOVQ acc1, t1 + MOVQ acc2, t2 + SUBQ $-5, acc0 + SBBQ $-1, acc1 + SBBQ $3, acc2 + CMOVQCS t0, acc0 + CMOVQCS t1, acc1 + CMOVQCS t2, acc2 + + // Add in the "s" part of the key + ADDQ 0+sStore, acc0 + ADCQ 8+sStore, acc1 + + // Finally, constant time compare to the tag at the end of the message + XORQ AX, AX + MOVQ $1, DX + XORQ (0*8)(inp), acc0 + XORQ (1*8)(inp), acc1 + ORQ acc1, acc0 + CMOVQEQ DX, AX + + // Return true iff tags are equal + MOVB AX, ret+96(FP) + RET + +// ---------------------------------------------------------------------------- +// Special optimization for buffers smaller than 129 bytes +openSSE128: + // For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks + MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0 + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 + MOVO B0, T1; MOVO C0, T2; MOVO D1, T3 + MOVQ $10, itr2 + +openSSE128InnerCipherLoop: + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Left; shiftB1Left; shiftB2Left + shiftC0Left; shiftC1Left; shiftC2Left + shiftD0Left; shiftD1Left; shiftD2Left + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Right; shiftB1Right; shiftB2Right + shiftC0Right; shiftC1Right; shiftC2Right + shiftD0Right; shiftD1Right; shiftD2Right + DECQ itr2 + JNE openSSE128InnerCipherLoop + + // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded + PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 + PADDL T1, B0; PADDL T1, B1; PADDL T1, B2 + PADDL T2, C1; PADDL T2, C2 + PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2 + + // Clamp and store the key + PAND ·polyClampMask<>(SB), A0 + MOVOU A0, rStore; MOVOU B0, sStore + + // Hash + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + +openSSE128Open: + CMPQ inl, $16 + JB openSSETail16 + SUBQ $16, inl + + // Load for hashing + polyAdd(0(inp)) + + // Load for decryption + MOVOU (inp), T0; PXOR T0, A1; MOVOU A1, (oup) + LEAQ (1*16)(inp), inp + LEAQ (1*16)(oup), oup + polyMul + + // Shift the stream "left" + MOVO B1, A1 + MOVO C1, B1 + MOVO D1, C1 + MOVO A2, D1 + MOVO B2, A2 + MOVO C2, B2 + MOVO D2, C2 + JMP openSSE128Open + +openSSETail16: + TESTQ inl, inl + JE openSSEFinalize + + // We can safely load the CT from the end, because it is padded with the MAC + MOVQ inl, itr2 + SHLQ $4, itr2 + LEAQ ·andMask<>(SB), t0 + MOVOU (inp), T0 + ADDQ inl, inp + PAND -16(t0)(itr2*1), T0 + MOVO T0, 0+tmpStore + MOVQ T0, t0 + MOVQ 8+tmpStore, t1 + PXOR A1, T0 + + // We can only store one byte at a time, since plaintext can be shorter than 16 bytes +openSSETail16Store: + MOVQ T0, t3 + MOVB t3, (oup) + PSRLDQ $1, T0 + INCQ oup + DECQ inl + JNE openSSETail16Store + ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 + polyMul + JMP openSSEFinalize + +// ---------------------------------------------------------------------------- +// Special optimization for the last 64 bytes of ciphertext +openSSETail64: + // Need to decrypt up to 64 bytes - prepare single block + MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store + XORQ itr2, itr2 + MOVQ inl, itr1 + CMPQ itr1, $16 + JB openSSETail64LoopB + +openSSETail64LoopA: + // Perform ChaCha rounds, while hashing the remaining input + polyAdd(0(inp)(itr2*1)) + polyMul + SUBQ $16, itr1 + +openSSETail64LoopB: + ADDQ $16, itr2 + chachaQR(A0, B0, C0, D0, T0) + shiftB0Left; shiftC0Left; shiftD0Left + chachaQR(A0, B0, C0, D0, T0) + shiftB0Right; shiftC0Right; shiftD0Right + + CMPQ itr1, $16 + JAE openSSETail64LoopA + + CMPQ itr2, $160 + JNE openSSETail64LoopB + + PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0; PADDL state2Store, C0; PADDL ctr0Store, D0 + +openSSETail64DecLoop: + CMPQ inl, $16 + JB openSSETail64DecLoopDone + SUBQ $16, inl + MOVOU (inp), T0 + PXOR T0, A0 + MOVOU A0, (oup) + LEAQ 16(inp), inp + LEAQ 16(oup), oup + MOVO B0, A0 + MOVO C0, B0 + MOVO D0, C0 + JMP openSSETail64DecLoop + +openSSETail64DecLoopDone: + MOVO A0, A1 + JMP openSSETail16 + +// ---------------------------------------------------------------------------- +// Special optimization for the last 128 bytes of ciphertext +openSSETail128: + // Need to decrypt up to 128 bytes - prepare two blocks + MOVO ·chacha20Constants<>(SB), A1; MOVO state1Store, B1; MOVO state2Store, C1; MOVO ctr3Store, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr0Store + MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr1Store + XORQ itr2, itr2 + MOVQ inl, itr1 + ANDQ $-16, itr1 + +openSSETail128LoopA: + // Perform ChaCha rounds, while hashing the remaining input + polyAdd(0(inp)(itr2*1)) + polyMul + +openSSETail128LoopB: + ADDQ $16, itr2 + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) + shiftB0Left; shiftC0Left; shiftD0Left + shiftB1Left; shiftC1Left; shiftD1Left + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) + shiftB0Right; shiftC0Right; shiftD0Right + shiftB1Right; shiftC1Right; shiftD1Right + + CMPQ itr2, itr1 + JB openSSETail128LoopA + + CMPQ itr2, $160 + JNE openSSETail128LoopB + + PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1 + PADDL state1Store, B0; PADDL state1Store, B1 + PADDL state2Store, C0; PADDL state2Store, C1 + PADDL ctr1Store, D0; PADDL ctr0Store, D1 + + MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 + PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1 + MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup) + + SUBQ $64, inl + LEAQ 64(inp), inp + LEAQ 64(oup), oup + JMP openSSETail64DecLoop + +// ---------------------------------------------------------------------------- +// Special optimization for the last 192 bytes of ciphertext +openSSETail192: + // Need to decrypt up to 192 bytes - prepare three blocks + MOVO ·chacha20Constants<>(SB), A2; MOVO state1Store, B2; MOVO state2Store, C2; MOVO ctr3Store, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr0Store + MOVO A2, A1; MOVO B2, B1; MOVO C2, C1; MOVO D2, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store + MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr2Store + + MOVQ inl, itr1 + MOVQ $160, itr2 + CMPQ itr1, $160 + CMOVQGT itr2, itr1 + ANDQ $-16, itr1 + XORQ itr2, itr2 + +openSSLTail192LoopA: + // Perform ChaCha rounds, while hashing the remaining input + polyAdd(0(inp)(itr2*1)) + polyMul + +openSSLTail192LoopB: + ADDQ $16, itr2 + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Left; shiftC0Left; shiftD0Left + shiftB1Left; shiftC1Left; shiftD1Left + shiftB2Left; shiftC2Left; shiftD2Left + + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Right; shiftC0Right; shiftD0Right + shiftB1Right; shiftC1Right; shiftD1Right + shiftB2Right; shiftC2Right; shiftD2Right + + CMPQ itr2, itr1 + JB openSSLTail192LoopA + + CMPQ itr2, $160 + JNE openSSLTail192LoopB + + CMPQ inl, $176 + JB openSSLTail192Store + + polyAdd(160(inp)) + polyMul + + CMPQ inl, $192 + JB openSSLTail192Store + + polyAdd(176(inp)) + polyMul + +openSSLTail192Store: + PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 + PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2 + PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2 + PADDL ctr2Store, D0; PADDL ctr1Store, D1; PADDL ctr0Store, D2 + + MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 + PXOR T0, A2; PXOR T1, B2; PXOR T2, C2; PXOR T3, D2 + MOVOU A2, (0*16)(oup); MOVOU B2, (1*16)(oup); MOVOU C2, (2*16)(oup); MOVOU D2, (3*16)(oup) + + MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3 + PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1 + MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) + + SUBQ $128, inl + LEAQ 128(inp), inp + LEAQ 128(oup), oup + JMP openSSETail64DecLoop + +// ---------------------------------------------------------------------------- +// Special optimization for the last 256 bytes of ciphertext +openSSETail256: + // Need to decrypt up to 256 bytes - prepare four blocks + MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0 + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 + MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + + // Store counters + MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store + XORQ itr2, itr2 + +openSSETail256Loop: + // This loop inteleaves 8 ChaCha quarter rounds with 1 poly multiplication + polyAdd(0(inp)(itr2*1)) + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left + shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left + shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left + polyMulStage1 + polyMulStage2 + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + polyMulStage3 + polyMulReduceStage + shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right + shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right + shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right + ADDQ $2*8, itr2 + CMPQ itr2, $160 + JB openSSETail256Loop + MOVQ inl, itr1 + ANDQ $-16, itr1 + +openSSETail256HashLoop: + polyAdd(0(inp)(itr2*1)) + polyMul + ADDQ $2*8, itr2 + CMPQ itr2, itr1 + JB openSSETail256HashLoop + + // Add in the state + PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 + PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 + PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 + PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 + MOVO D3, tmpStore + + // Load - xor - store + MOVOU (0*16)(inp), D3; PXOR D3, A0 + MOVOU (1*16)(inp), D3; PXOR D3, B0 + MOVOU (2*16)(inp), D3; PXOR D3, C0 + MOVOU (3*16)(inp), D3; PXOR D3, D0 + MOVOU A0, (0*16)(oup) + MOVOU B0, (1*16)(oup) + MOVOU C0, (2*16)(oup) + MOVOU D0, (3*16)(oup) + MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0 + PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1 + MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) + MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0 + PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2 + MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup) + LEAQ 192(inp), inp + LEAQ 192(oup), oup + SUBQ $192, inl + MOVO A3, A0 + MOVO B3, B0 + MOVO C3, C0 + MOVO tmpStore, D0 + + JMP openSSETail64DecLoop + +// ---------------------------------------------------------------------------- +// ------------------------- AVX2 Code ---------------------------------------- +chacha20Poly1305Open_AVX2: + VZEROUPPER + VMOVDQU ·chacha20Constants<>(SB), AA0 + BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14 + BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12 + BYTE $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4 + VPADDD ·avx2InitMask<>(SB), DD0, DD0 + + // Special optimization, for very short buffers + CMPQ inl, $192 + JBE openAVX2192 + CMPQ inl, $320 + JBE openAVX2320 + + // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream + VMOVDQA BB0, state1StoreAVX2 + VMOVDQA CC0, state2StoreAVX2 + VMOVDQA DD0, ctr3StoreAVX2 + MOVQ $10, itr2 + +openAVX2PreparePolyKey: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0 + DECQ itr2 + JNE openAVX2PreparePolyKey + + VPADDD ·chacha20Constants<>(SB), AA0, AA0 + VPADDD state1StoreAVX2, BB0, BB0 + VPADDD state2StoreAVX2, CC0, CC0 + VPADDD ctr3StoreAVX2, DD0, DD0 + + VPERM2I128 $0x02, AA0, BB0, TT0 + + // Clamp and store poly key + VPAND ·polyClampMask<>(SB), TT0, TT0 + VMOVDQA TT0, rsStoreAVX2 + + // Stream for the first 64 bytes + VPERM2I128 $0x13, AA0, BB0, AA0 + VPERM2I128 $0x13, CC0, DD0, BB0 + + // Hash AD + first 64 bytes + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + XORQ itr1, itr1 + +openAVX2InitialHash64: + polyAdd(0(inp)(itr1*1)) + polyMulAVX2 + ADDQ $16, itr1 + CMPQ itr1, $64 + JNE openAVX2InitialHash64 + + // Decrypt the first 64 bytes + VPXOR (0*32)(inp), AA0, AA0 + VPXOR (1*32)(inp), BB0, BB0 + VMOVDQU AA0, (0*32)(oup) + VMOVDQU BB0, (1*32)(oup) + LEAQ (2*32)(inp), inp + LEAQ (2*32)(oup), oup + SUBQ $64, inl + +openAVX2MainLoop: + CMPQ inl, $512 + JB openAVX2MainLoopDone + + // Load state, increment counter blocks, store the incremented counters + VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 + VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 + VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 + XORQ itr1, itr1 + +openAVX2InternalLoop: + // Lets just say this spaghetti loop interleaves 2 quarter rounds with 3 poly multiplications + // Effectively per 512 bytes of stream we hash 480 bytes of ciphertext + polyAdd(0*8(inp)(itr1*1)) + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + polyMulStage1_AVX2 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + polyMulStage2_AVX2 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + polyMulStage3_AVX2 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulReduceStage + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + polyAdd(2*8(inp)(itr1*1)) + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + polyMulStage1_AVX2 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulStage2_AVX2 + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + polyMulStage3_AVX2 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + polyMulReduceStage + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + polyAdd(4*8(inp)(itr1*1)) + LEAQ (6*8)(itr1), itr1 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulStage1_AVX2 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + polyMulStage2_AVX2 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + polyMulStage3_AVX2 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulReduceStage + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 + CMPQ itr1, $480 + JNE openAVX2InternalLoop + + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 + VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 + VMOVDQA CC3, tmpStoreAVX2 + + // We only hashed 480 of the 512 bytes available - hash the remaining 32 here + polyAdd(480(inp)) + polyMulAVX2 + VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0 + VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0 + VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup) + VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 + VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) + + // and here + polyAdd(496(inp)) + polyMulAVX2 + VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 + VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 + VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) + VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 + VPXOR (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0 + VMOVDQU AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup) + LEAQ (32*16)(inp), inp + LEAQ (32*16)(oup), oup + SUBQ $(32*16), inl + JMP openAVX2MainLoop + +openAVX2MainLoopDone: + // Handle the various tail sizes efficiently + TESTQ inl, inl + JE openSSEFinalize + CMPQ inl, $128 + JBE openAVX2Tail128 + CMPQ inl, $256 + JBE openAVX2Tail256 + CMPQ inl, $384 + JBE openAVX2Tail384 + JMP openAVX2Tail512 + +// ---------------------------------------------------------------------------- +// Special optimization for buffers smaller than 193 bytes +openAVX2192: + // For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks + VMOVDQA AA0, AA1 + VMOVDQA BB0, BB1 + VMOVDQA CC0, CC1 + VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VMOVDQA AA0, AA2 + VMOVDQA BB0, BB2 + VMOVDQA CC0, CC2 + VMOVDQA DD0, DD2 + VMOVDQA DD1, TT3 + MOVQ $10, itr2 + +openAVX2192InnerCipherLoop: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 + DECQ itr2 + JNE openAVX2192InnerCipherLoop + VPADDD AA2, AA0, AA0; VPADDD AA2, AA1, AA1 + VPADDD BB2, BB0, BB0; VPADDD BB2, BB1, BB1 + VPADDD CC2, CC0, CC0; VPADDD CC2, CC1, CC1 + VPADDD DD2, DD0, DD0; VPADDD TT3, DD1, DD1 + VPERM2I128 $0x02, AA0, BB0, TT0 + + // Clamp and store poly key + VPAND ·polyClampMask<>(SB), TT0, TT0 + VMOVDQA TT0, rsStoreAVX2 + + // Stream for up to 192 bytes + VPERM2I128 $0x13, AA0, BB0, AA0 + VPERM2I128 $0x13, CC0, DD0, BB0 + VPERM2I128 $0x02, AA1, BB1, CC0 + VPERM2I128 $0x02, CC1, DD1, DD0 + VPERM2I128 $0x13, AA1, BB1, AA1 + VPERM2I128 $0x13, CC1, DD1, BB1 + +openAVX2ShortOpen: + // Hash + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + +openAVX2ShortOpenLoop: + CMPQ inl, $32 + JB openAVX2ShortTail32 + SUBQ $32, inl + + // Load for hashing + polyAdd(0*8(inp)) + polyMulAVX2 + polyAdd(2*8(inp)) + polyMulAVX2 + + // Load for decryption + VPXOR (inp), AA0, AA0 + VMOVDQU AA0, (oup) + LEAQ (1*32)(inp), inp + LEAQ (1*32)(oup), oup + + // Shift stream left + VMOVDQA BB0, AA0 + VMOVDQA CC0, BB0 + VMOVDQA DD0, CC0 + VMOVDQA AA1, DD0 + VMOVDQA BB1, AA1 + VMOVDQA CC1, BB1 + VMOVDQA DD1, CC1 + VMOVDQA AA2, DD1 + VMOVDQA BB2, AA2 + JMP openAVX2ShortOpenLoop + +openAVX2ShortTail32: + CMPQ inl, $16 + VMOVDQA A0, A1 + JB openAVX2ShortDone + + SUBQ $16, inl + + // Load for hashing + polyAdd(0*8(inp)) + polyMulAVX2 + + // Load for decryption + VPXOR (inp), A0, T0 + VMOVDQU T0, (oup) + LEAQ (1*16)(inp), inp + LEAQ (1*16)(oup), oup + VPERM2I128 $0x11, AA0, AA0, AA0 + VMOVDQA A0, A1 + +openAVX2ShortDone: + VZEROUPPER + JMP openSSETail16 + +// ---------------------------------------------------------------------------- +// Special optimization for buffers smaller than 321 bytes +openAVX2320: + // For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks + VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2 + VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3 + MOVQ $10, itr2 + +openAVX2320InnerCipherLoop: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 + DECQ itr2 + JNE openAVX2320InnerCipherLoop + + VMOVDQA ·chacha20Constants<>(SB), TT0 + VPADDD TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2 + VPADDD TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2 + VPADDD TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2 + VMOVDQA ·avx2IncMask<>(SB), TT0 + VPADDD TT3, DD0, DD0; VPADDD TT0, TT3, TT3 + VPADDD TT3, DD1, DD1; VPADDD TT0, TT3, TT3 + VPADDD TT3, DD2, DD2 + + // Clamp and store poly key + VPERM2I128 $0x02, AA0, BB0, TT0 + VPAND ·polyClampMask<>(SB), TT0, TT0 + VMOVDQA TT0, rsStoreAVX2 + + // Stream for up to 320 bytes + VPERM2I128 $0x13, AA0, BB0, AA0 + VPERM2I128 $0x13, CC0, DD0, BB0 + VPERM2I128 $0x02, AA1, BB1, CC0 + VPERM2I128 $0x02, CC1, DD1, DD0 + VPERM2I128 $0x13, AA1, BB1, AA1 + VPERM2I128 $0x13, CC1, DD1, BB1 + VPERM2I128 $0x02, AA2, BB2, CC1 + VPERM2I128 $0x02, CC2, DD2, DD1 + VPERM2I128 $0x13, AA2, BB2, AA2 + VPERM2I128 $0x13, CC2, DD2, BB2 + JMP openAVX2ShortOpen + +// ---------------------------------------------------------------------------- +// Special optimization for the last 128 bytes of ciphertext +openAVX2Tail128: + // Need to decrypt up to 128 bytes - prepare two blocks + VMOVDQA ·chacha20Constants<>(SB), AA1 + VMOVDQA state1StoreAVX2, BB1 + VMOVDQA state2StoreAVX2, CC1 + VMOVDQA ctr3StoreAVX2, DD1 + VPADDD ·avx2IncMask<>(SB), DD1, DD1 + VMOVDQA DD1, DD0 + + XORQ itr2, itr2 + MOVQ inl, itr1 + ANDQ $-16, itr1 + TESTQ itr1, itr1 + JE openAVX2Tail128LoopB + +openAVX2Tail128LoopA: + // Perform ChaCha rounds, while hashing the remaining input + polyAdd(0(inp)(itr2*1)) + polyMulAVX2 + +openAVX2Tail128LoopB: + ADDQ $16, itr2 + chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $4, BB1, BB1, BB1 + VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $12, DD1, DD1, DD1 + chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $12, BB1, BB1, BB1 + VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $4, DD1, DD1, DD1 + CMPQ itr2, itr1 + JB openAVX2Tail128LoopA + CMPQ itr2, $160 + JNE openAVX2Tail128LoopB + + VPADDD ·chacha20Constants<>(SB), AA1, AA1 + VPADDD state1StoreAVX2, BB1, BB1 + VPADDD state2StoreAVX2, CC1, CC1 + VPADDD DD0, DD1, DD1 + VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + +openAVX2TailLoop: + CMPQ inl, $32 + JB openAVX2Tail + SUBQ $32, inl + + // Load for decryption + VPXOR (inp), AA0, AA0 + VMOVDQU AA0, (oup) + LEAQ (1*32)(inp), inp + LEAQ (1*32)(oup), oup + VMOVDQA BB0, AA0 + VMOVDQA CC0, BB0 + VMOVDQA DD0, CC0 + JMP openAVX2TailLoop + +openAVX2Tail: + CMPQ inl, $16 + VMOVDQA A0, A1 + JB openAVX2TailDone + SUBQ $16, inl + + // Load for decryption + VPXOR (inp), A0, T0 + VMOVDQU T0, (oup) + LEAQ (1*16)(inp), inp + LEAQ (1*16)(oup), oup + VPERM2I128 $0x11, AA0, AA0, AA0 + VMOVDQA A0, A1 + +openAVX2TailDone: + VZEROUPPER + JMP openSSETail16 + +// ---------------------------------------------------------------------------- +// Special optimization for the last 256 bytes of ciphertext +openAVX2Tail256: + // Need to decrypt up to 256 bytes - prepare four blocks + VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VMOVDQA DD0, TT1 + VMOVDQA DD1, TT2 + + // Compute the number of iterations that will hash data + MOVQ inl, tmpStoreAVX2 + MOVQ inl, itr1 + SUBQ $128, itr1 + SHRQ $4, itr1 + MOVQ $10, itr2 + CMPQ itr1, $10 + CMOVQGT itr2, itr1 + MOVQ inp, inl + XORQ itr2, itr2 + +openAVX2Tail256LoopA: + polyAdd(0(inl)) + polyMulAVX2 + LEAQ 16(inl), inl + + // Perform ChaCha rounds, while hashing the remaining input +openAVX2Tail256LoopB: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 + INCQ itr2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 + CMPQ itr2, itr1 + JB openAVX2Tail256LoopA + + CMPQ itr2, $10 + JNE openAVX2Tail256LoopB + + MOVQ inl, itr2 + SUBQ inp, inl + MOVQ inl, itr1 + MOVQ tmpStoreAVX2, inl + + // Hash the remainder of data (if any) +openAVX2Tail256Hash: + ADDQ $16, itr1 + CMPQ itr1, inl + JGT openAVX2Tail256HashEnd + polyAdd (0(itr2)) + polyMulAVX2 + LEAQ 16(itr2), itr2 + JMP openAVX2Tail256Hash + +// Store 128 bytes safely, then go to store loop +openAVX2Tail256HashEnd: + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1 + VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1 + VPERM2I128 $0x02, AA0, BB0, AA2; VPERM2I128 $0x02, CC0, DD0, BB2; VPERM2I128 $0x13, AA0, BB0, CC2; VPERM2I128 $0x13, CC0, DD0, DD2 + VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + + VPXOR (0*32)(inp), AA2, AA2; VPXOR (1*32)(inp), BB2, BB2; VPXOR (2*32)(inp), CC2, CC2; VPXOR (3*32)(inp), DD2, DD2 + VMOVDQU AA2, (0*32)(oup); VMOVDQU BB2, (1*32)(oup); VMOVDQU CC2, (2*32)(oup); VMOVDQU DD2, (3*32)(oup) + LEAQ (4*32)(inp), inp + LEAQ (4*32)(oup), oup + SUBQ $4*32, inl + + JMP openAVX2TailLoop + +// ---------------------------------------------------------------------------- +// Special optimization for the last 384 bytes of ciphertext +openAVX2Tail384: + // Need to decrypt up to 384 bytes - prepare six blocks + VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VPADDD ·avx2IncMask<>(SB), DD1, DD2 + VMOVDQA DD0, ctr0StoreAVX2 + VMOVDQA DD1, ctr1StoreAVX2 + VMOVDQA DD2, ctr2StoreAVX2 + + // Compute the number of iterations that will hash two blocks of data + MOVQ inl, tmpStoreAVX2 + MOVQ inl, itr1 + SUBQ $256, itr1 + SHRQ $4, itr1 + ADDQ $6, itr1 + MOVQ $10, itr2 + CMPQ itr1, $10 + CMOVQGT itr2, itr1 + MOVQ inp, inl + XORQ itr2, itr2 + + // Perform ChaCha rounds, while hashing the remaining input +openAVX2Tail384LoopB: + polyAdd(0(inl)) + polyMulAVX2 + LEAQ 16(inl), inl + +openAVX2Tail384LoopA: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 + polyAdd(0(inl)) + polyMulAVX2 + LEAQ 16(inl), inl + INCQ itr2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 + + CMPQ itr2, itr1 + JB openAVX2Tail384LoopB + + CMPQ itr2, $10 + JNE openAVX2Tail384LoopA + + MOVQ inl, itr2 + SUBQ inp, inl + MOVQ inl, itr1 + MOVQ tmpStoreAVX2, inl + +openAVX2Tail384Hash: + ADDQ $16, itr1 + CMPQ itr1, inl + JGT openAVX2Tail384HashEnd + polyAdd(0(itr2)) + polyMulAVX2 + LEAQ 16(itr2), itr2 + JMP openAVX2Tail384Hash + +// Store 256 bytes safely, then go to store loop +openAVX2Tail384HashEnd: + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2 + VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2 + VPERM2I128 $0x02, AA0, BB0, TT0; VPERM2I128 $0x02, CC0, DD0, TT1; VPERM2I128 $0x13, AA0, BB0, TT2; VPERM2I128 $0x13, CC0, DD0, TT3 + VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3 + VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup) + VPERM2I128 $0x02, AA1, BB1, TT0; VPERM2I128 $0x02, CC1, DD1, TT1; VPERM2I128 $0x13, AA1, BB1, TT2; VPERM2I128 $0x13, CC1, DD1, TT3 + VPXOR (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3 + VMOVDQU TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup) + VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 + LEAQ (8*32)(inp), inp + LEAQ (8*32)(oup), oup + SUBQ $8*32, inl + JMP openAVX2TailLoop + +// ---------------------------------------------------------------------------- +// Special optimization for the last 512 bytes of ciphertext +openAVX2Tail512: + VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 + VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 + VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 + XORQ itr1, itr1 + MOVQ inp, itr2 + +openAVX2Tail512LoopB: + polyAdd(0(itr2)) + polyMulAVX2 + LEAQ (2*8)(itr2), itr2 + +openAVX2Tail512LoopA: + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyAdd(0*8(itr2)) + polyMulAVX2 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + polyAdd(2*8(itr2)) + polyMulAVX2 + LEAQ (4*8)(itr2), itr2 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 + INCQ itr1 + CMPQ itr1, $4 + JLT openAVX2Tail512LoopB + + CMPQ itr1, $10 + JNE openAVX2Tail512LoopA + + MOVQ inl, itr1 + SUBQ $384, itr1 + ANDQ $-16, itr1 + +openAVX2Tail512HashLoop: + TESTQ itr1, itr1 + JE openAVX2Tail512HashEnd + polyAdd(0(itr2)) + polyMulAVX2 + LEAQ 16(itr2), itr2 + SUBQ $16, itr1 + JMP openAVX2Tail512HashLoop + +openAVX2Tail512HashEnd: + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 + VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 + VMOVDQA CC3, tmpStoreAVX2 + VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0 + VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0 + VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup) + VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 + VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) + VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 + VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 + VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) + VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 + + LEAQ (12*32)(inp), inp + LEAQ (12*32)(oup), oup + SUBQ $12*32, inl + + JMP openAVX2TailLoop + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// func chacha20Poly1305Seal(dst, key, src, ad []byte) +TEXT ·chacha20Poly1305Seal(SB), 0, $288-96 + // For aligned stack access + MOVQ SP, BP + ADDQ $32, BP + ANDQ $-32, BP + MOVQ dst+0(FP), oup + MOVQ key+24(FP), keyp + MOVQ src+48(FP), inp + MOVQ src_len+56(FP), inl + MOVQ ad+72(FP), adp + + CMPB ·useAVX2(SB), $1 + JE chacha20Poly1305Seal_AVX2 + + // Special optimization, for very short buffers + CMPQ inl, $128 + JBE sealSSE128 // About 15% faster + + // In the seal case - prepare the poly key + 3 blocks of stream in the first iteration + MOVOU ·chacha20Constants<>(SB), A0 + MOVOU (1*16)(keyp), B0 + MOVOU (2*16)(keyp), C0 + MOVOU (3*16)(keyp), D0 + + // Store state on stack for future use + MOVO B0, state1Store + MOVO C0, state2Store + + // Load state, increment counter blocks + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 + MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + + // Store counters + MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store + MOVQ $10, itr2 + +sealSSEIntroLoop: + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left + shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left + shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left + + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right + shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right + shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right + DECQ itr2 + JNE sealSSEIntroLoop + + // Add in the state + PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 + PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 + PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 + PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 + + // Clamp and store the key + PAND ·polyClampMask<>(SB), A0 + MOVO A0, rStore + MOVO B0, sStore + + // Hash AAD + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + + MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0 + PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1 + MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup) + MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0 + PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2 + MOVOU A2, (4*16)(oup); MOVOU B2, (5*16)(oup); MOVOU C2, (6*16)(oup); MOVOU D2, (7*16)(oup) + + MOVQ $128, itr1 + SUBQ $128, inl + LEAQ 128(inp), inp + + MOVO A3, A1; MOVO B3, B1; MOVO C3, C1; MOVO D3, D1 + + CMPQ inl, $64 + JBE sealSSE128SealHash + + MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0 + PXOR A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3 + MOVOU A3, (8*16)(oup); MOVOU B3, (9*16)(oup); MOVOU C3, (10*16)(oup); MOVOU D3, (11*16)(oup) + + ADDQ $64, itr1 + SUBQ $64, inl + LEAQ 64(inp), inp + + MOVQ $2, itr1 + MOVQ $8, itr2 + + CMPQ inl, $64 + JBE sealSSETail64 + CMPQ inl, $128 + JBE sealSSETail128 + CMPQ inl, $192 + JBE sealSSETail192 + +sealSSEMainLoop: + // Load state, increment counter blocks + MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0 + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 + MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3 + + // Store counters + MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store + +sealSSEInnerLoop: + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + polyAdd(0(oup)) + shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left + shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left + shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left + polyMulStage1 + polyMulStage2 + LEAQ (2*8)(oup), oup + MOVO C3, tmpStore + chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3) + MOVO tmpStore, C3 + MOVO C1, tmpStore + polyMulStage3 + chachaQR(A3, B3, C3, D3, C1) + MOVO tmpStore, C1 + polyMulReduceStage + shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right + shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right + shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right + DECQ itr2 + JGE sealSSEInnerLoop + polyAdd(0(oup)) + polyMul + LEAQ (2*8)(oup), oup + DECQ itr1 + JG sealSSEInnerLoop + + // Add in the state + PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3 + PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3 + PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3 + PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3 + MOVO D3, tmpStore + + // Load - xor - store + MOVOU (0*16)(inp), D3; PXOR D3, A0 + MOVOU (1*16)(inp), D3; PXOR D3, B0 + MOVOU (2*16)(inp), D3; PXOR D3, C0 + MOVOU (3*16)(inp), D3; PXOR D3, D0 + MOVOU A0, (0*16)(oup) + MOVOU B0, (1*16)(oup) + MOVOU C0, (2*16)(oup) + MOVOU D0, (3*16)(oup) + MOVO tmpStore, D3 + + MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0 + PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1 + MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) + MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0 + PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2 + MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup) + ADDQ $192, inp + MOVQ $192, itr1 + SUBQ $192, inl + MOVO A3, A1 + MOVO B3, B1 + MOVO C3, C1 + MOVO D3, D1 + CMPQ inl, $64 + JBE sealSSE128SealHash + MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0 + PXOR A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3 + MOVOU A3, (12*16)(oup); MOVOU B3, (13*16)(oup); MOVOU C3, (14*16)(oup); MOVOU D3, (15*16)(oup) + LEAQ 64(inp), inp + SUBQ $64, inl + MOVQ $6, itr1 + MOVQ $4, itr2 + CMPQ inl, $192 + JG sealSSEMainLoop + + MOVQ inl, itr1 + TESTQ inl, inl + JE sealSSE128SealHash + MOVQ $6, itr1 + CMPQ inl, $64 + JBE sealSSETail64 + CMPQ inl, $128 + JBE sealSSETail128 + JMP sealSSETail192 + +// ---------------------------------------------------------------------------- +// Special optimization for the last 64 bytes of plaintext +sealSSETail64: + // Need to encrypt up to 64 bytes - prepare single block, hash 192 or 256 bytes + MOVO ·chacha20Constants<>(SB), A1 + MOVO state1Store, B1 + MOVO state2Store, C1 + MOVO ctr3Store, D1 + PADDL ·sseIncMask<>(SB), D1 + MOVO D1, ctr0Store + +sealSSETail64LoopA: + // Perform ChaCha rounds, while hashing the previously encrypted ciphertext + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealSSETail64LoopB: + chachaQR(A1, B1, C1, D1, T1) + shiftB1Left; shiftC1Left; shiftD1Left + chachaQR(A1, B1, C1, D1, T1) + shiftB1Right; shiftC1Right; shiftD1Right + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + + DECQ itr1 + JG sealSSETail64LoopA + + DECQ itr2 + JGE sealSSETail64LoopB + PADDL ·chacha20Constants<>(SB), A1 + PADDL state1Store, B1 + PADDL state2Store, C1 + PADDL ctr0Store, D1 + + JMP sealSSE128Seal + +// ---------------------------------------------------------------------------- +// Special optimization for the last 128 bytes of plaintext +sealSSETail128: + // Need to encrypt up to 128 bytes - prepare two blocks, hash 192 or 256 bytes + MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store + +sealSSETail128LoopA: + // Perform ChaCha rounds, while hashing the previously encrypted ciphertext + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealSSETail128LoopB: + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) + shiftB0Left; shiftC0Left; shiftD0Left + shiftB1Left; shiftC1Left; shiftD1Left + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0) + shiftB0Right; shiftC0Right; shiftD0Right + shiftB1Right; shiftC1Right; shiftD1Right + + DECQ itr1 + JG sealSSETail128LoopA + + DECQ itr2 + JGE sealSSETail128LoopB + + PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1 + PADDL state1Store, B0; PADDL state1Store, B1 + PADDL state2Store, C0; PADDL state2Store, C1 + PADDL ctr0Store, D0; PADDL ctr1Store, D1 + + MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 + PXOR T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0 + MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup) + + MOVQ $64, itr1 + LEAQ 64(inp), inp + SUBQ $64, inl + + JMP sealSSE128SealHash + +// ---------------------------------------------------------------------------- +// Special optimization for the last 192 bytes of plaintext +sealSSETail192: + // Need to encrypt up to 192 bytes - prepare three blocks, hash 192 or 256 bytes + MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr2Store + +sealSSETail192LoopA: + // Perform ChaCha rounds, while hashing the previously encrypted ciphertext + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealSSETail192LoopB: + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Left; shiftC0Left; shiftD0Left + shiftB1Left; shiftC1Left; shiftD1Left + shiftB2Left; shiftC2Left; shiftD2Left + + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Right; shiftC0Right; shiftD0Right + shiftB1Right; shiftC1Right; shiftD1Right + shiftB2Right; shiftC2Right; shiftD2Right + + DECQ itr1 + JG sealSSETail192LoopA + + DECQ itr2 + JGE sealSSETail192LoopB + + PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 + PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2 + PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2 + PADDL ctr0Store, D0; PADDL ctr1Store, D1; PADDL ctr2Store, D2 + + MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3 + PXOR T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0 + MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup) + MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3 + PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1 + MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup) + + MOVO A2, A1 + MOVO B2, B1 + MOVO C2, C1 + MOVO D2, D1 + MOVQ $128, itr1 + LEAQ 128(inp), inp + SUBQ $128, inl + + JMP sealSSE128SealHash + +// ---------------------------------------------------------------------------- +// Special seal optimization for buffers smaller than 129 bytes +sealSSE128: + // For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks + MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0 + MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1 + MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2 + MOVO B0, T1; MOVO C0, T2; MOVO D1, T3 + MOVQ $10, itr2 + +sealSSE128InnerCipherLoop: + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Left; shiftB1Left; shiftB2Left + shiftC0Left; shiftC1Left; shiftC2Left + shiftD0Left; shiftD1Left; shiftD2Left + chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0) + shiftB0Right; shiftB1Right; shiftB2Right + shiftC0Right; shiftC1Right; shiftC2Right + shiftD0Right; shiftD1Right; shiftD2Right + DECQ itr2 + JNE sealSSE128InnerCipherLoop + + // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded + PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2 + PADDL T1, B0; PADDL T1, B1; PADDL T1, B2 + PADDL T2, C1; PADDL T2, C2 + PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2 + PAND ·polyClampMask<>(SB), A0 + MOVOU A0, rStore + MOVOU B0, sStore + + // Hash + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + XORQ itr1, itr1 + +sealSSE128SealHash: + // itr1 holds the number of bytes encrypted but not yet hashed + CMPQ itr1, $16 + JB sealSSE128Seal + polyAdd(0(oup)) + polyMul + + SUBQ $16, itr1 + ADDQ $16, oup + + JMP sealSSE128SealHash + +sealSSE128Seal: + CMPQ inl, $16 + JB sealSSETail + SUBQ $16, inl + + // Load for decryption + MOVOU (inp), T0 + PXOR T0, A1 + MOVOU A1, (oup) + LEAQ (1*16)(inp), inp + LEAQ (1*16)(oup), oup + + // Extract for hashing + MOVQ A1, t0 + PSRLDQ $8, A1 + MOVQ A1, t1 + ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 + polyMul + + // Shift the stream "left" + MOVO B1, A1 + MOVO C1, B1 + MOVO D1, C1 + MOVO A2, D1 + MOVO B2, A2 + MOVO C2, B2 + MOVO D2, C2 + JMP sealSSE128Seal + +sealSSETail: + TESTQ inl, inl + JE sealSSEFinalize + + // We can only load the PT one byte at a time to avoid read after end of buffer + MOVQ inl, itr2 + SHLQ $4, itr2 + LEAQ ·andMask<>(SB), t0 + MOVQ inl, itr1 + LEAQ -1(inp)(inl*1), inp + XORQ t2, t2 + XORQ t3, t3 + XORQ AX, AX + +sealSSETailLoadLoop: + SHLQ $8, t2, t3 + SHLQ $8, t2 + MOVB (inp), AX + XORQ AX, t2 + LEAQ -1(inp), inp + DECQ itr1 + JNE sealSSETailLoadLoop + MOVQ t2, 0+tmpStore + MOVQ t3, 8+tmpStore + PXOR 0+tmpStore, A1 + MOVOU A1, (oup) + MOVOU -16(t0)(itr2*1), T0 + PAND T0, A1 + MOVQ A1, t0 + PSRLDQ $8, A1 + MOVQ A1, t1 + ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2 + polyMul + + ADDQ inl, oup + +sealSSEFinalize: + // Hash in the buffer lengths + ADDQ ad_len+80(FP), acc0 + ADCQ src_len+56(FP), acc1 + ADCQ $1, acc2 + polyMul + + // Final reduce + MOVQ acc0, t0 + MOVQ acc1, t1 + MOVQ acc2, t2 + SUBQ $-5, acc0 + SBBQ $-1, acc1 + SBBQ $3, acc2 + CMOVQCS t0, acc0 + CMOVQCS t1, acc1 + CMOVQCS t2, acc2 + + // Add in the "s" part of the key + ADDQ 0+sStore, acc0 + ADCQ 8+sStore, acc1 + + // Finally store the tag at the end of the message + MOVQ acc0, (0*8)(oup) + MOVQ acc1, (1*8)(oup) + RET + +// ---------------------------------------------------------------------------- +// ------------------------- AVX2 Code ---------------------------------------- +chacha20Poly1305Seal_AVX2: + VZEROUPPER + VMOVDQU ·chacha20Constants<>(SB), AA0 + BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14 + BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12 + BYTE $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4 + VPADDD ·avx2InitMask<>(SB), DD0, DD0 + + // Special optimizations, for very short buffers + CMPQ inl, $192 + JBE seal192AVX2 // 33% faster + CMPQ inl, $320 + JBE seal320AVX2 // 17% faster + + // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream + VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 + VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3; VMOVDQA BB0, state1StoreAVX2 + VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3; VMOVDQA CC0, state2StoreAVX2 + VPADDD ·avx2IncMask<>(SB), DD0, DD1; VMOVDQA DD0, ctr0StoreAVX2 + VPADDD ·avx2IncMask<>(SB), DD1, DD2; VMOVDQA DD1, ctr1StoreAVX2 + VPADDD ·avx2IncMask<>(SB), DD2, DD3; VMOVDQA DD2, ctr2StoreAVX2 + VMOVDQA DD3, ctr3StoreAVX2 + MOVQ $10, itr2 + +sealAVX2IntroLoop: + VMOVDQA CC3, tmpStoreAVX2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) + VMOVDQA tmpStoreAVX2, CC3 + VMOVDQA CC1, tmpStoreAVX2 + chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) + VMOVDQA tmpStoreAVX2, CC1 + + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0 + VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1 + VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2 + VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3 + + VMOVDQA CC3, tmpStoreAVX2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) + VMOVDQA tmpStoreAVX2, CC3 + VMOVDQA CC1, tmpStoreAVX2 + chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) + VMOVDQA tmpStoreAVX2, CC1 + + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0 + VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1 + VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2 + VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3 + DECQ itr2 + JNE sealAVX2IntroLoop + + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 + VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 + + VPERM2I128 $0x13, CC0, DD0, CC0 // Stream bytes 96 - 127 + VPERM2I128 $0x02, AA0, BB0, DD0 // The Poly1305 key + VPERM2I128 $0x13, AA0, BB0, AA0 // Stream bytes 64 - 95 + + // Clamp and store poly key + VPAND ·polyClampMask<>(SB), DD0, DD0 + VMOVDQA DD0, rsStoreAVX2 + + // Hash AD + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + + // Can store at least 320 bytes + VPXOR (0*32)(inp), AA0, AA0 + VPXOR (1*32)(inp), CC0, CC0 + VMOVDQU AA0, (0*32)(oup) + VMOVDQU CC0, (1*32)(oup) + + VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + VPXOR (2*32)(inp), AA0, AA0; VPXOR (3*32)(inp), BB0, BB0; VPXOR (4*32)(inp), CC0, CC0; VPXOR (5*32)(inp), DD0, DD0 + VMOVDQU AA0, (2*32)(oup); VMOVDQU BB0, (3*32)(oup); VMOVDQU CC0, (4*32)(oup); VMOVDQU DD0, (5*32)(oup) + VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 + VPXOR (6*32)(inp), AA0, AA0; VPXOR (7*32)(inp), BB0, BB0; VPXOR (8*32)(inp), CC0, CC0; VPXOR (9*32)(inp), DD0, DD0 + VMOVDQU AA0, (6*32)(oup); VMOVDQU BB0, (7*32)(oup); VMOVDQU CC0, (8*32)(oup); VMOVDQU DD0, (9*32)(oup) + + MOVQ $320, itr1 + SUBQ $320, inl + LEAQ 320(inp), inp + + VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, CC3, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, CC3, DD3, DD0 + CMPQ inl, $128 + JBE sealAVX2SealHash + + VPXOR (0*32)(inp), AA0, AA0; VPXOR (1*32)(inp), BB0, BB0; VPXOR (2*32)(inp), CC0, CC0; VPXOR (3*32)(inp), DD0, DD0 + VMOVDQU AA0, (10*32)(oup); VMOVDQU BB0, (11*32)(oup); VMOVDQU CC0, (12*32)(oup); VMOVDQU DD0, (13*32)(oup) + SUBQ $128, inl + LEAQ 128(inp), inp + + MOVQ $8, itr1 + MOVQ $2, itr2 + + CMPQ inl, $128 + JBE sealAVX2Tail128 + CMPQ inl, $256 + JBE sealAVX2Tail256 + CMPQ inl, $384 + JBE sealAVX2Tail384 + CMPQ inl, $512 + JBE sealAVX2Tail512 + + // We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop + VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 + VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 + + VMOVDQA CC3, tmpStoreAVX2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) + VMOVDQA tmpStoreAVX2, CC3 + VMOVDQA CC1, tmpStoreAVX2 + chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) + VMOVDQA tmpStoreAVX2, CC1 + + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0 + VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1 + VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2 + VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3 + + VMOVDQA CC3, tmpStoreAVX2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3) + VMOVDQA tmpStoreAVX2, CC3 + VMOVDQA CC1, tmpStoreAVX2 + chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1) + VMOVDQA tmpStoreAVX2, CC1 + + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0 + VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1 + VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2 + VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + + SUBQ $16, oup // Adjust the pointer + MOVQ $9, itr1 + JMP sealAVX2InternalLoopStart + +sealAVX2MainLoop: + // Load state, increment counter blocks, store the incremented counters + VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 + VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 + VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 + MOVQ $10, itr1 + +sealAVX2InternalLoop: + polyAdd(0*8(oup)) + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + polyMulStage1_AVX2 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + polyMulStage2_AVX2 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + polyMulStage3_AVX2 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulReduceStage + +sealAVX2InternalLoopStart: + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + polyAdd(2*8(oup)) + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + polyMulStage1_AVX2 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulStage2_AVX2 + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + polyMulStage3_AVX2 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + polyMulReduceStage + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + polyAdd(4*8(oup)) + LEAQ (6*8)(oup), oup + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulStage1_AVX2 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + polyMulStage2_AVX2 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + polyMulStage3_AVX2 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyMulReduceStage + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 + DECQ itr1 + JNE sealAVX2InternalLoop + + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 + VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 + VMOVDQA CC3, tmpStoreAVX2 + + // We only hashed 480 of the 512 bytes available - hash the remaining 32 here + polyAdd(0*8(oup)) + polyMulAVX2 + LEAQ (4*8)(oup), oup + VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0 + VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0 + VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup) + VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0 + VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 + VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) + + // and here + polyAdd(-2*8(oup)) + polyMulAVX2 + VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0 + VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 + VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) + VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 + VPXOR (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0 + VMOVDQU AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup) + LEAQ (32*16)(inp), inp + SUBQ $(32*16), inl + CMPQ inl, $512 + JG sealAVX2MainLoop + + // Tail can only hash 480 bytes + polyAdd(0*8(oup)) + polyMulAVX2 + polyAdd(2*8(oup)) + polyMulAVX2 + LEAQ 32(oup), oup + + MOVQ $10, itr1 + MOVQ $0, itr2 + CMPQ inl, $128 + JBE sealAVX2Tail128 + CMPQ inl, $256 + JBE sealAVX2Tail256 + CMPQ inl, $384 + JBE sealAVX2Tail384 + JMP sealAVX2Tail512 + +// ---------------------------------------------------------------------------- +// Special optimization for buffers smaller than 193 bytes +seal192AVX2: + // For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks + VMOVDQA AA0, AA1 + VMOVDQA BB0, BB1 + VMOVDQA CC0, CC1 + VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VMOVDQA AA0, AA2 + VMOVDQA BB0, BB2 + VMOVDQA CC0, CC2 + VMOVDQA DD0, DD2 + VMOVDQA DD1, TT3 + MOVQ $10, itr2 + +sealAVX2192InnerCipherLoop: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 + DECQ itr2 + JNE sealAVX2192InnerCipherLoop + VPADDD AA2, AA0, AA0; VPADDD AA2, AA1, AA1 + VPADDD BB2, BB0, BB0; VPADDD BB2, BB1, BB1 + VPADDD CC2, CC0, CC0; VPADDD CC2, CC1, CC1 + VPADDD DD2, DD0, DD0; VPADDD TT3, DD1, DD1 + VPERM2I128 $0x02, AA0, BB0, TT0 + + // Clamp and store poly key + VPAND ·polyClampMask<>(SB), TT0, TT0 + VMOVDQA TT0, rsStoreAVX2 + + // Stream for up to 192 bytes + VPERM2I128 $0x13, AA0, BB0, AA0 + VPERM2I128 $0x13, CC0, DD0, BB0 + VPERM2I128 $0x02, AA1, BB1, CC0 + VPERM2I128 $0x02, CC1, DD1, DD0 + VPERM2I128 $0x13, AA1, BB1, AA1 + VPERM2I128 $0x13, CC1, DD1, BB1 + +sealAVX2ShortSeal: + // Hash aad + MOVQ ad_len+80(FP), itr2 + CALL polyHashADInternal<>(SB) + XORQ itr1, itr1 + +sealAVX2SealHash: + // itr1 holds the number of bytes encrypted but not yet hashed + CMPQ itr1, $16 + JB sealAVX2ShortSealLoop + polyAdd(0(oup)) + polyMul + SUBQ $16, itr1 + ADDQ $16, oup + JMP sealAVX2SealHash + +sealAVX2ShortSealLoop: + CMPQ inl, $32 + JB sealAVX2ShortTail32 + SUBQ $32, inl + + // Load for encryption + VPXOR (inp), AA0, AA0 + VMOVDQU AA0, (oup) + LEAQ (1*32)(inp), inp + + // Now can hash + polyAdd(0*8(oup)) + polyMulAVX2 + polyAdd(2*8(oup)) + polyMulAVX2 + LEAQ (1*32)(oup), oup + + // Shift stream left + VMOVDQA BB0, AA0 + VMOVDQA CC0, BB0 + VMOVDQA DD0, CC0 + VMOVDQA AA1, DD0 + VMOVDQA BB1, AA1 + VMOVDQA CC1, BB1 + VMOVDQA DD1, CC1 + VMOVDQA AA2, DD1 + VMOVDQA BB2, AA2 + JMP sealAVX2ShortSealLoop + +sealAVX2ShortTail32: + CMPQ inl, $16 + VMOVDQA A0, A1 + JB sealAVX2ShortDone + + SUBQ $16, inl + + // Load for encryption + VPXOR (inp), A0, T0 + VMOVDQU T0, (oup) + LEAQ (1*16)(inp), inp + + // Hash + polyAdd(0*8(oup)) + polyMulAVX2 + LEAQ (1*16)(oup), oup + VPERM2I128 $0x11, AA0, AA0, AA0 + VMOVDQA A0, A1 + +sealAVX2ShortDone: + VZEROUPPER + JMP sealSSETail + +// ---------------------------------------------------------------------------- +// Special optimization for buffers smaller than 321 bytes +seal320AVX2: + // For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks + VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2 + VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3 + MOVQ $10, itr2 + +sealAVX2320InnerCipherLoop: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 + DECQ itr2 + JNE sealAVX2320InnerCipherLoop + + VMOVDQA ·chacha20Constants<>(SB), TT0 + VPADDD TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2 + VPADDD TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2 + VPADDD TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2 + VMOVDQA ·avx2IncMask<>(SB), TT0 + VPADDD TT3, DD0, DD0; VPADDD TT0, TT3, TT3 + VPADDD TT3, DD1, DD1; VPADDD TT0, TT3, TT3 + VPADDD TT3, DD2, DD2 + + // Clamp and store poly key + VPERM2I128 $0x02, AA0, BB0, TT0 + VPAND ·polyClampMask<>(SB), TT0, TT0 + VMOVDQA TT0, rsStoreAVX2 + + // Stream for up to 320 bytes + VPERM2I128 $0x13, AA0, BB0, AA0 + VPERM2I128 $0x13, CC0, DD0, BB0 + VPERM2I128 $0x02, AA1, BB1, CC0 + VPERM2I128 $0x02, CC1, DD1, DD0 + VPERM2I128 $0x13, AA1, BB1, AA1 + VPERM2I128 $0x13, CC1, DD1, BB1 + VPERM2I128 $0x02, AA2, BB2, CC1 + VPERM2I128 $0x02, CC2, DD2, DD1 + VPERM2I128 $0x13, AA2, BB2, AA2 + VPERM2I128 $0x13, CC2, DD2, BB2 + JMP sealAVX2ShortSeal + +// ---------------------------------------------------------------------------- +// Special optimization for the last 128 bytes of ciphertext +sealAVX2Tail128: + // Need to decrypt up to 128 bytes - prepare two blocks + // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed + // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed + VMOVDQA ·chacha20Constants<>(SB), AA0 + VMOVDQA state1StoreAVX2, BB0 + VMOVDQA state2StoreAVX2, CC0 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0 + VMOVDQA DD0, DD1 + +sealAVX2Tail128LoopA: + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealAVX2Tail128LoopB: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) + polyAdd(0(oup)) + polyMul + VPALIGNR $4, BB0, BB0, BB0 + VPALIGNR $8, CC0, CC0, CC0 + VPALIGNR $12, DD0, DD0, DD0 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0) + polyAdd(16(oup)) + polyMul + LEAQ 32(oup), oup + VPALIGNR $12, BB0, BB0, BB0 + VPALIGNR $8, CC0, CC0, CC0 + VPALIGNR $4, DD0, DD0, DD0 + DECQ itr1 + JG sealAVX2Tail128LoopA + DECQ itr2 + JGE sealAVX2Tail128LoopB + + VPADDD ·chacha20Constants<>(SB), AA0, AA1 + VPADDD state1StoreAVX2, BB0, BB1 + VPADDD state2StoreAVX2, CC0, CC1 + VPADDD DD1, DD0, DD1 + + VPERM2I128 $0x02, AA1, BB1, AA0 + VPERM2I128 $0x02, CC1, DD1, BB0 + VPERM2I128 $0x13, AA1, BB1, CC0 + VPERM2I128 $0x13, CC1, DD1, DD0 + JMP sealAVX2ShortSealLoop + +// ---------------------------------------------------------------------------- +// Special optimization for the last 256 bytes of ciphertext +sealAVX2Tail256: + // Need to decrypt up to 256 bytes - prepare two blocks + // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed + // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed + VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA ·chacha20Constants<>(SB), AA1 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA state1StoreAVX2, BB1 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA state2StoreAVX2, CC1 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD1 + VMOVDQA DD0, TT1 + VMOVDQA DD1, TT2 + +sealAVX2Tail256LoopA: + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealAVX2Tail256LoopB: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + polyAdd(0(oup)) + polyMul + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0) + polyAdd(16(oup)) + polyMul + LEAQ 32(oup), oup + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1 + DECQ itr1 + JG sealAVX2Tail256LoopA + DECQ itr2 + JGE sealAVX2Tail256LoopB + + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1 + VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1 + VPERM2I128 $0x02, AA0, BB0, TT0 + VPERM2I128 $0x02, CC0, DD0, TT1 + VPERM2I128 $0x13, AA0, BB0, TT2 + VPERM2I128 $0x13, CC0, DD0, TT3 + VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3 + VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup) + MOVQ $128, itr1 + LEAQ 128(inp), inp + SUBQ $128, inl + VPERM2I128 $0x02, AA1, BB1, AA0 + VPERM2I128 $0x02, CC1, DD1, BB0 + VPERM2I128 $0x13, AA1, BB1, CC0 + VPERM2I128 $0x13, CC1, DD1, DD0 + + JMP sealAVX2SealHash + +// ---------------------------------------------------------------------------- +// Special optimization for the last 384 bytes of ciphertext +sealAVX2Tail384: + // Need to decrypt up to 384 bytes - prepare two blocks + // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed + // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed + VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2 + VMOVDQA DD0, TT1; VMOVDQA DD1, TT2; VMOVDQA DD2, TT3 + +sealAVX2Tail384LoopA: + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealAVX2Tail384LoopB: + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + polyAdd(0(oup)) + polyMul + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2 + chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0) + polyAdd(16(oup)) + polyMul + LEAQ 32(oup), oup + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2 + DECQ itr1 + JG sealAVX2Tail384LoopA + DECQ itr2 + JGE sealAVX2Tail384LoopB + + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2 + VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1; VPADDD TT3, DD2, DD2 + VPERM2I128 $0x02, AA0, BB0, TT0 + VPERM2I128 $0x02, CC0, DD0, TT1 + VPERM2I128 $0x13, AA0, BB0, TT2 + VPERM2I128 $0x13, CC0, DD0, TT3 + VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3 + VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup) + VPERM2I128 $0x02, AA1, BB1, TT0 + VPERM2I128 $0x02, CC1, DD1, TT1 + VPERM2I128 $0x13, AA1, BB1, TT2 + VPERM2I128 $0x13, CC1, DD1, TT3 + VPXOR (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3 + VMOVDQU TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup) + MOVQ $256, itr1 + LEAQ 256(inp), inp + SUBQ $256, inl + VPERM2I128 $0x02, AA2, BB2, AA0 + VPERM2I128 $0x02, CC2, DD2, BB0 + VPERM2I128 $0x13, AA2, BB2, CC0 + VPERM2I128 $0x13, CC2, DD2, DD0 + + JMP sealAVX2SealHash + +// ---------------------------------------------------------------------------- +// Special optimization for the last 512 bytes of ciphertext +sealAVX2Tail512: + // Need to decrypt up to 512 bytes - prepare two blocks + // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed + // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed + VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3 + VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3 + VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3 + VMOVDQA ctr3StoreAVX2, DD0 + VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3 + VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2 + +sealAVX2Tail512LoopA: + polyAdd(0(oup)) + polyMul + LEAQ 16(oup), oup + +sealAVX2Tail512LoopB: + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + polyAdd(0*8(oup)) + polyMulAVX2 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + polyAdd(2*8(oup)) + polyMulAVX2 + LEAQ (4*8)(oup), oup + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3 + VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3 + VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3 + VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3 + VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3 + VMOVDQA CC3, tmpStoreAVX2 + VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0 + VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1 + VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2 + VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3 + VMOVDQA tmpStoreAVX2, CC3 + VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3 + VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3 + VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3 + + DECQ itr1 + JG sealAVX2Tail512LoopA + DECQ itr2 + JGE sealAVX2Tail512LoopB + + VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3 + VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3 + VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3 + VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3 + VMOVDQA CC3, tmpStoreAVX2 + VPERM2I128 $0x02, AA0, BB0, CC3 + VPXOR (0*32)(inp), CC3, CC3 + VMOVDQU CC3, (0*32)(oup) + VPERM2I128 $0x02, CC0, DD0, CC3 + VPXOR (1*32)(inp), CC3, CC3 + VMOVDQU CC3, (1*32)(oup) + VPERM2I128 $0x13, AA0, BB0, CC3 + VPXOR (2*32)(inp), CC3, CC3 + VMOVDQU CC3, (2*32)(oup) + VPERM2I128 $0x13, CC0, DD0, CC3 + VPXOR (3*32)(inp), CC3, CC3 + VMOVDQU CC3, (3*32)(oup) + + VPERM2I128 $0x02, AA1, BB1, AA0 + VPERM2I128 $0x02, CC1, DD1, BB0 + VPERM2I128 $0x13, AA1, BB1, CC0 + VPERM2I128 $0x13, CC1, DD1, DD0 + VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0 + VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup) + + VPERM2I128 $0x02, AA2, BB2, AA0 + VPERM2I128 $0x02, CC2, DD2, BB0 + VPERM2I128 $0x13, AA2, BB2, CC0 + VPERM2I128 $0x13, CC2, DD2, DD0 + VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0 + VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup) + + MOVQ $384, itr1 + LEAQ 384(inp), inp + SUBQ $384, inl + VPERM2I128 $0x02, AA3, BB3, AA0 + VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0 + VPERM2I128 $0x13, AA3, BB3, CC0 + VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0 + + JMP sealAVX2SealHash diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go new file mode 100644 index 000000000..c27971216 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go @@ -0,0 +1,81 @@ +// 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. + +package chacha20poly1305 + +import ( + "encoding/binary" + + "golang.org/x/crypto/internal/chacha20" + "golang.org/x/crypto/internal/subtle" + "golang.org/x/crypto/poly1305" +) + +func roundTo16(n int) int { + return 16 * ((n + 15) / 16) +} + +func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte { + ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize) + if subtle.InexactOverlap(out, plaintext) { + panic("chacha20poly1305: invalid buffer overlap") + } + + var polyKey [32]byte + s := chacha20.New(c.key, [3]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + }) + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip the next 32 bytes + s.XORKeyStream(out, plaintext) + + polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8) + copy(polyInput, additionalData) + copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)]) + binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData))) + binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext))) + + var tag [poly1305.TagSize]byte + poly1305.Sum(&tag, polyInput, &polyKey) + copy(out[len(plaintext):], tag[:]) + + return ret +} + +func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + var tag [poly1305.TagSize]byte + copy(tag[:], ciphertext[len(ciphertext)-16:]) + ciphertext = ciphertext[:len(ciphertext)-16] + + var polyKey [32]byte + s := chacha20.New(c.key, [3]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + }) + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip the next 32 bytes + + polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8) + copy(polyInput, additionalData) + copy(polyInput[roundTo16(len(additionalData)):], ciphertext) + binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData))) + binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext))) + + ret, out := sliceForAppend(dst, len(ciphertext)) + if subtle.InexactOverlap(out, ciphertext) { + panic("chacha20poly1305: invalid buffer overlap") + } + if !poly1305.Verify(&tag, polyInput, &polyKey) { + for i := range out { + out[i] = 0 + } + return nil, errOpen + } + + s.XORKeyStream(out, ciphertext) + return ret, nil +} diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go new file mode 100644 index 000000000..4c2eb703c --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go @@ -0,0 +1,15 @@ +// 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 !amd64 !go1.7 gccgo appengine + +package chacha20poly1305 + +func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte { + return c.sealGeneric(dst, nonce, plaintext, additionalData) +} + +func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + return c.openGeneric(dst, nonce, ciphertext, additionalData) +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1.go new file mode 100644 index 000000000..528b9bff6 --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1.go @@ -0,0 +1,751 @@ +// Copyright 2017 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 cryptobyte + +import ( + encoding_asn1 "encoding/asn1" + "fmt" + "math/big" + "reflect" + "time" + + "golang.org/x/crypto/cryptobyte/asn1" +) + +// This file contains ASN.1-related methods for String and Builder. + +// Builder + +// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Int64(v int64) { + b.addASN1Signed(asn1.INTEGER, v) +} + +// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the +// given tag. +func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) { + b.addASN1Signed(tag, v) +} + +// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION. +func (b *Builder) AddASN1Enum(v int64) { + b.addASN1Signed(asn1.ENUM, v) +} + +func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) { + b.AddASN1(tag, func(c *Builder) { + length := 1 + for i := v; i >= 0x80 || i < -0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1Uint64(v uint64) { + b.AddASN1(asn1.INTEGER, func(c *Builder) { + length := 1 + for i := v; i >= 0x80; i >>= 8 { + length++ + } + + for ; length > 0; length-- { + i := v >> uint((length-1)*8) & 0xff + c.AddUint8(uint8(i)) + } + }) +} + +// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER. +func (b *Builder) AddASN1BigInt(n *big.Int) { + if b.err != nil { + return + } + + b.AddASN1(asn1.INTEGER, func(c *Builder) { + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement form. So we + // invert and subtract 1. If the most-significant-bit isn't set then + // we'll need to pad the beginning with 0xff in order to keep the number + // negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if bytes[0]&0x80 == 0 { + c.add(0xff) + } + c.add(bytes...) + } else if n.Sign() == 0 { + c.add(0) + } else { + bytes := n.Bytes() + if bytes[0]&0x80 != 0 { + c.add(0) + } + c.add(bytes...) + } + }) +} + +// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING. +func (b *Builder) AddASN1OctetString(bytes []byte) { + b.AddASN1(asn1.OCTET_STRING, func(c *Builder) { + c.AddBytes(bytes) + }) +} + +const generalizedTimeFormatStr = "20060102150405Z0700" + +// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME. +func (b *Builder) AddASN1GeneralizedTime(t time.Time) { + if t.Year() < 0 || t.Year() > 9999 { + b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t) + return + } + b.AddASN1(asn1.GeneralizedTime, func(c *Builder) { + c.AddBytes([]byte(t.Format(generalizedTimeFormatStr))) + }) +} + +// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not +// support BIT STRINGs that are not a whole number of bytes. +func (b *Builder) AddASN1BitString(data []byte) { + b.AddASN1(asn1.BIT_STRING, func(b *Builder) { + b.AddUint8(0) + b.AddBytes(data) + }) +} + +func (b *Builder) addBase128Int(n int64) { + var length int + if n == 0 { + length = 1 + } else { + for i := n; i > 0; i >>= 7 { + length++ + } + } + + for i := length - 1; i >= 0; i-- { + o := byte(n >> uint(i*7)) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + + b.add(o) + } +} + +func isValidOID(oid encoding_asn1.ObjectIdentifier) bool { + if len(oid) < 2 { + return false + } + + if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) { + return false + } + + for _, v := range oid { + if v < 0 { + return false + } + } + + return true +} + +func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) { + b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) { + if !isValidOID(oid) { + b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid) + return + } + + b.addBase128Int(int64(oid[0])*40 + int64(oid[1])) + for _, v := range oid[2:] { + b.addBase128Int(int64(v)) + } + }) +} + +func (b *Builder) AddASN1Boolean(v bool) { + b.AddASN1(asn1.BOOLEAN, func(b *Builder) { + if v { + b.AddUint8(0xff) + } else { + b.AddUint8(0) + } + }) +} + +func (b *Builder) AddASN1NULL() { + b.add(uint8(asn1.NULL), 0) +} + +// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if +// successful or records an error if one occurred. +func (b *Builder) MarshalASN1(v interface{}) { + // NOTE(martinkr): This is somewhat of a hack to allow propagation of + // encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a + // value embedded into a struct, its tag information is lost. + if b.err != nil { + return + } + bytes, err := encoding_asn1.Marshal(v) + if err != nil { + b.err = err + return + } + b.AddBytes(bytes) +} + +// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag. +// Tags greater than 30 are not supported and result in an error (i.e. +// low-tag-number form only). The child builder passed to the +// BuilderContinuation can be used to build the content of the ASN.1 object. +func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) { + if b.err != nil { + return + } + // Identifiers with the low five bits set indicate high-tag-number format + // (two or more octets), which we don't support. + if tag&0x1f == 0x1f { + b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag) + return + } + b.AddUint8(uint8(tag)) + b.addLengthPrefixed(1, true, f) +} + +// String + +// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean +// representation into out and advances. It reports whether the read +// was successful. +func (s *String) ReadASN1Boolean(out *bool) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 { + return false + } + + switch bytes[0] { + case 0: + *out = false + case 0xff: + *out = true + default: + return false + } + + return true +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() + +// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does +// not point to an integer or to a big.Int, it panics. It reports whether the +// read was successful. +func (s *String) ReadASN1Integer(out interface{}) bool { + if reflect.TypeOf(out).Kind() != reflect.Ptr { + panic("out is not a pointer") + } + switch reflect.ValueOf(out).Elem().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + var i int64 + if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) { + return false + } + reflect.ValueOf(out).Elem().SetInt(i) + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + var u uint64 + if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) { + return false + } + reflect.ValueOf(out).Elem().SetUint(u) + return true + case reflect.Struct: + if reflect.TypeOf(out).Elem() == bigIntType { + return s.readASN1BigInt(out.(*big.Int)) + } + } + panic("out does not point to an integer type") +} + +func checkASN1Integer(bytes []byte) bool { + if len(bytes) == 0 { + // An INTEGER is encoded with at least one octet. + return false + } + if len(bytes) == 1 { + return true + } + if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 { + // Value is not minimally encoded. + return false + } + return true +} + +var bigOne = big.NewInt(1) + +func (s *String) readASN1BigInt(out *big.Int) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + // Negative number. + neg := make([]byte, len(bytes)) + for i, b := range bytes { + neg[i] = ^b + } + out.SetBytes(neg) + out.Add(out, bigOne) + out.Neg(out) + } else { + out.SetBytes(bytes) + } + return true +} + +func (s *String) readASN1Int64(out *int64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) { + return false + } + return true +} + +func asn1Signed(out *int64, n []byte) bool { + length := len(n) + if length > 8 { + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= int64(n[i]) + } + // Shift up and down in order to sign extend the result. + *out <<= 64 - uint8(length)*8 + *out >>= 64 - uint8(length)*8 + return true +} + +func (s *String) readASN1Uint64(out *uint64) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) { + return false + } + return true +} + +func asn1Unsigned(out *uint64, n []byte) bool { + length := len(n) + if length > 9 || length == 9 && n[0] != 0 { + // Too large for uint64. + return false + } + if n[0]&0x80 != 0 { + // Negative number. + return false + } + for i := 0; i < length; i++ { + *out <<= 8 + *out |= uint64(n[i]) + } + return true +} + +// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out +// and advances. It reports whether the read was successful and resulted in a +// value that can be represented in an int64. +func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool { + var bytes String + return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes) +} + +// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports +// whether the read was successful. +func (s *String) ReadASN1Enum(out *int) bool { + var bytes String + var i int64 + if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) { + return false + } + if int64(int(i)) != i { + return false + } + *out = int(i) + return true +} + +func (s *String) readBase128Int(out *int) bool { + ret := 0 + for i := 0; len(*s) > 0; i++ { + if i == 4 { + return false + } + ret <<= 7 + b := s.read(1)[0] + ret |= int(b & 0x7f) + if b&0x80 == 0 { + *out = ret + return true + } + } + return false // truncated +} + +// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and +// advances. It reports whether the read was successful. +func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 { + return false + } + + // In the worst case, we get two elements from the first byte (which is + // encoded differently) and then every varint is a single byte long. + components := make([]int, len(bytes)+1) + + // The first varint is 40*value1 + value2: + // According to this packing, value1 can take the values 0, 1 and 2 only. + // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2, + // then there are no restrictions on value2. + var v int + if !bytes.readBase128Int(&v) { + return false + } + if v < 80 { + components[0] = v / 40 + components[1] = v % 40 + } else { + components[0] = 2 + components[1] = v - 80 + } + + i := 2 + for ; len(bytes) > 0; i++ { + if !bytes.readBase128Int(&v) { + return false + } + components[i] = v + } + *out = components[:i] + return true +} + +// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and +// advances. It reports whether the read was successful. +func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.GeneralizedTime) { + return false + } + t := string(bytes) + res, err := time.Parse(generalizedTimeFormatStr, t) + if err != nil { + return false + } + if serialized := res.Format(generalizedTimeFormatStr); serialized != t { + return false + } + *out = res + return true +} + +// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. +// It reports whether the read was successful. +func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 { + return false + } + + paddingBits := uint8(bytes[0]) + bytes = bytes[1:] + if paddingBits > 7 || + len(bytes) == 0 && paddingBits != 0 || + len(bytes) > 0 && bytes[len(bytes)-1]&(1< 4 || len(*s) < int(2+lenLen) { + return false + } + + lenBytes := String((*s)[2 : 2+lenLen]) + if !lenBytes.readUnsigned(&len32, int(lenLen)) { + return false + } + + // ITU-T X.690 section 10.1 (DER length forms) requires encoding the length + // with the minimum number of octets. + if len32 < 128 { + // Length should have used short-form encoding. + return false + } + if len32>>((lenLen-1)*8) == 0 { + // Leading octet is 0. Length should have been at least one byte shorter. + return false + } + + headerLen = 2 + uint32(lenLen) + if headerLen+len32 < len32 { + // Overflow. + return false + } + length = headerLen + len32 + } + + if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) { + return false + } + if skipHeader && !out.Skip(int(headerLen)) { + panic("cryptobyte: internal error") + } + + return true +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go new file mode 100644 index 000000000..cda8e3edf --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go @@ -0,0 +1,46 @@ +// Copyright 2017 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 asn1 contains supporting types for parsing and building ASN.1 +// messages with the cryptobyte package. +package asn1 // import "golang.org/x/crypto/cryptobyte/asn1" + +// Tag represents an ASN.1 identifier octet, consisting of a tag number +// (indicating a type) and class (such as context-specific or constructed). +// +// Methods in the cryptobyte package only support the low-tag-number form, i.e. +// a single identifier octet with bits 7-8 encoding the class and bits 1-6 +// encoding the tag number. +type Tag uint8 + +const ( + classConstructed = 0x20 + classContextSpecific = 0x80 +) + +// Constructed returns t with the constructed class bit set. +func (t Tag) Constructed() Tag { return t | classConstructed } + +// ContextSpecific returns t with the context-specific class bit set. +func (t Tag) ContextSpecific() Tag { return t | classContextSpecific } + +// The following is a list of standard tag and class combinations. +const ( + BOOLEAN = Tag(1) + INTEGER = Tag(2) + BIT_STRING = Tag(3) + OCTET_STRING = Tag(4) + NULL = Tag(5) + OBJECT_IDENTIFIER = Tag(6) + ENUM = Tag(10) + UTF8String = Tag(12) + SEQUENCE = Tag(16 | classConstructed) + SET = Tag(17 | classConstructed) + PrintableString = Tag(19) + T61String = Tag(20) + IA5String = Tag(22) + UTCTime = Tag(23) + GeneralizedTime = Tag(24) + GeneralString = Tag(27) +) diff --git a/vendor/golang.org/x/crypto/cryptobyte/builder.go b/vendor/golang.org/x/crypto/cryptobyte/builder.go new file mode 100644 index 000000000..29b4c7641 --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/builder.go @@ -0,0 +1,309 @@ +// Copyright 2017 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 cryptobyte + +import ( + "errors" + "fmt" +) + +// A Builder builds byte strings from fixed-length and length-prefixed values. +// Builders either allocate space as needed, or are ‘fixed’, which means that +// they write into a given buffer and produce an error if it's exhausted. +// +// The zero value is a usable Builder that allocates space as needed. +// +// Simple values are marshaled and appended to a Builder using methods on the +// Builder. Length-prefixed values are marshaled by providing a +// BuilderContinuation, which is a function that writes the inner contents of +// the value to a given Builder. See the documentation for BuilderContinuation +// for details. +type Builder struct { + err error + result []byte + fixedSize bool + child *Builder + offset int + pendingLenLen int + pendingIsASN1 bool + inContinuation *bool +} + +// NewBuilder creates a Builder that appends its output to the given buffer. +// Like append(), the slice will be reallocated if its capacity is exceeded. +// Use Bytes to get the final buffer. +func NewBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + } +} + +// NewFixedBuilder creates a Builder that appends its output into the given +// buffer. This builder does not reallocate the output buffer. Writes that +// would exceed the buffer's capacity are treated as an error. +func NewFixedBuilder(buffer []byte) *Builder { + return &Builder{ + result: buffer, + fixedSize: true, + } +} + +// Bytes returns the bytes written by the builder or an error if one has +// occurred during during building. +func (b *Builder) Bytes() ([]byte, error) { + if b.err != nil { + return nil, b.err + } + return b.result[b.offset:], nil +} + +// BytesOrPanic returns the bytes written by the builder or panics if an error +// has occurred during building. +func (b *Builder) BytesOrPanic() []byte { + if b.err != nil { + panic(b.err) + } + return b.result[b.offset:] +} + +// AddUint8 appends an 8-bit value to the byte string. +func (b *Builder) AddUint8(v uint8) { + b.add(byte(v)) +} + +// AddUint16 appends a big-endian, 16-bit value to the byte string. +func (b *Builder) AddUint16(v uint16) { + b.add(byte(v>>8), byte(v)) +} + +// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest +// byte of the 32-bit input value is silently truncated. +func (b *Builder) AddUint24(v uint32) { + b.add(byte(v>>16), byte(v>>8), byte(v)) +} + +// AddUint32 appends a big-endian, 32-bit value to the byte string. +func (b *Builder) AddUint32(v uint32) { + b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// AddBytes appends a sequence of bytes to the byte string. +func (b *Builder) AddBytes(v []byte) { + b.add(v...) +} + +// BuilderContinuation is continuation-passing interface for building +// length-prefixed byte sequences. Builder methods for length-prefixed +// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation +// supplied to them. The child builder passed to the continuation can be used +// to build the content of the length-prefixed sequence. For example: +// +// parent := cryptobyte.NewBuilder() +// parent.AddUint8LengthPrefixed(func (child *Builder) { +// child.AddUint8(42) +// child.AddUint8LengthPrefixed(func (grandchild *Builder) { +// grandchild.AddUint8(5) +// }) +// }) +// +// It is an error to write more bytes to the child than allowed by the reserved +// length prefix. After the continuation returns, the child must be considered +// invalid, i.e. users must not store any copies or references of the child +// that outlive the continuation. +// +// If the continuation panics with a value of type BuildError then the inner +// error will be returned as the error from Bytes. If the child panics +// otherwise then Bytes will repanic with the same value. +type BuilderContinuation func(child *Builder) + +// BuildError wraps an error. If a BuilderContinuation panics with this value, +// the panic will be recovered and the inner error will be returned from +// Builder.Bytes. +type BuildError struct { + Err error +} + +// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence. +func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(1, false, f) +} + +// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence. +func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(2, false, f) +} + +// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence. +func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(3, false, f) +} + +// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence. +func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) { + b.addLengthPrefixed(4, false, f) +} + +func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) { + if !*b.inContinuation { + *b.inContinuation = true + + defer func() { + *b.inContinuation = false + + r := recover() + if r == nil { + return + } + + if buildError, ok := r.(BuildError); ok { + b.err = buildError.Err + } else { + panic(r) + } + }() + } + + f(arg) +} + +func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) { + // Subsequent writes can be ignored if the builder has encountered an error. + if b.err != nil { + return + } + + offset := len(b.result) + b.add(make([]byte, lenLen)...) + + if b.inContinuation == nil { + b.inContinuation = new(bool) + } + + b.child = &Builder{ + result: b.result, + fixedSize: b.fixedSize, + offset: offset, + pendingLenLen: lenLen, + pendingIsASN1: isASN1, + inContinuation: b.inContinuation, + } + + b.callContinuation(f, b.child) + b.flushChild() + if b.child != nil { + panic("cryptobyte: internal error") + } +} + +func (b *Builder) flushChild() { + if b.child == nil { + return + } + b.child.flushChild() + child := b.child + b.child = nil + + if child.err != nil { + b.err = child.err + return + } + + length := len(child.result) - child.pendingLenLen - child.offset + + if length < 0 { + panic("cryptobyte: internal error") // result unexpectedly shrunk + } + + if child.pendingIsASN1 { + // For ASN.1, we reserved a single byte for the length. If that turned out + // to be incorrect, we have to move the contents along in order to make + // space. + if child.pendingLenLen != 1 { + panic("cryptobyte: internal error") + } + var lenLen, lenByte uint8 + if int64(length) > 0xfffffffe { + b.err = errors.New("pending ASN.1 child too long") + return + } else if length > 0xffffff { + lenLen = 5 + lenByte = 0x80 | 4 + } else if length > 0xffff { + lenLen = 4 + lenByte = 0x80 | 3 + } else if length > 0xff { + lenLen = 3 + lenByte = 0x80 | 2 + } else if length > 0x7f { + lenLen = 2 + lenByte = 0x80 | 1 + } else { + lenLen = 1 + lenByte = uint8(length) + length = 0 + } + + // Insert the initial length byte, make space for successive length bytes, + // and adjust the offset. + child.result[child.offset] = lenByte + extraBytes := int(lenLen - 1) + if extraBytes != 0 { + child.add(make([]byte, extraBytes)...) + childStart := child.offset + child.pendingLenLen + copy(child.result[childStart+extraBytes:], child.result[childStart:]) + } + child.offset++ + child.pendingLenLen = extraBytes + } + + l := length + for i := child.pendingLenLen - 1; i >= 0; i-- { + child.result[child.offset+i] = uint8(l) + l >>= 8 + } + if l != 0 { + b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen) + return + } + + if !b.fixedSize { + b.result = child.result // In case child reallocated result. + } +} + +func (b *Builder) add(bytes ...byte) { + if b.err != nil { + return + } + if b.child != nil { + panic("attempted write while child is pending") + } + if len(b.result)+len(bytes) < len(bytes) { + b.err = errors.New("cryptobyte: length overflow") + } + if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) { + b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer") + return + } + b.result = append(b.result, bytes...) +} + +// A MarshalingValue marshals itself into a Builder. +type MarshalingValue interface { + // Marshal is called by Builder.AddValue. It receives a pointer to a builder + // to marshal itself into. It may return an error that occurred during + // marshaling, such as unset or invalid values. + Marshal(b *Builder) error +} + +// AddValue calls Marshal on v, passing a pointer to the builder to append to. +// If Marshal returns an error, it is set on the Builder so that subsequent +// appends don't have an effect. +func (b *Builder) AddValue(v MarshalingValue) { + err := v.Marshal(b) + if err != nil { + b.err = err + } +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/string.go b/vendor/golang.org/x/crypto/cryptobyte/string.go new file mode 100644 index 000000000..39bf98aee --- /dev/null +++ b/vendor/golang.org/x/crypto/cryptobyte/string.go @@ -0,0 +1,166 @@ +// Copyright 2017 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 cryptobyte contains types that help with parsing and constructing +// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage +// contains useful ASN.1 constants.) +// +// The String type is for parsing. It wraps a []byte slice and provides helper +// functions for consuming structures, value by value. +// +// The Builder type is for constructing messages. It providers helper functions +// for appending values and also for appending length-prefixed submessages – +// without having to worry about calculating the length prefix ahead of time. +// +// See the documentation and examples for the Builder and String types to get +// started. +package cryptobyte // import "golang.org/x/crypto/cryptobyte" + +// String represents a string of bytes. It provides methods for parsing +// fixed-length and length-prefixed values from it. +type String []byte + +// read advances a String by n bytes and returns them. If less than n bytes +// remain, it returns nil. +func (s *String) read(n int) []byte { + if len(*s) < n { + return nil + } + v := (*s)[:n] + *s = (*s)[n:] + return v +} + +// Skip advances the String by n byte and reports whether it was successful. +func (s *String) Skip(n int) bool { + return s.read(n) != nil +} + +// ReadUint8 decodes an 8-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint8(out *uint8) bool { + v := s.read(1) + if v == nil { + return false + } + *out = uint8(v[0]) + return true +} + +// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint16(out *uint16) bool { + v := s.read(2) + if v == nil { + return false + } + *out = uint16(v[0])<<8 | uint16(v[1]) + return true +} + +// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint24(out *uint32) bool { + v := s.read(3) + if v == nil { + return false + } + *out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2]) + return true +} + +// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. +// It reports whether the read was successful. +func (s *String) ReadUint32(out *uint32) bool { + v := s.read(4) + if v == nil { + return false + } + *out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3]) + return true +} + +func (s *String) readUnsigned(out *uint32, length int) bool { + v := s.read(length) + if v == nil { + return false + } + var result uint32 + for i := 0; i < length; i++ { + result <<= 8 + result |= uint32(v[i]) + } + *out = result + return true +} + +func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool { + lenBytes := s.read(lenLen) + if lenBytes == nil { + return false + } + var length uint32 + for _, b := range lenBytes { + length = length << 8 + length = length | uint32(b) + } + if int(length) < 0 { + // This currently cannot overflow because we read uint24 at most, but check + // anyway in case that changes in the future. + return false + } + v := s.read(int(length)) + if v == nil { + return false + } + *outChild = v + return true +} + +// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value +// into out and advances over it. It reports whether the read was successful. +func (s *String) ReadUint8LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(1, out) +} + +// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit +// length-prefixed value into out and advances over it. It reports whether the +// read was successful. +func (s *String) ReadUint16LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(2, out) +} + +// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit +// length-prefixed value into out and advances over it. It reports whether +// the read was successful. +func (s *String) ReadUint24LengthPrefixed(out *String) bool { + return s.readLengthPrefixed(3, out) +} + +// ReadBytes reads n bytes into out and advances over them. It reports +// whether the read was successful. +func (s *String) ReadBytes(out *[]byte, n int) bool { + v := s.read(n) + if v == nil { + return false + } + *out = v + return true +} + +// CopyBytes copies len(out) bytes into out and advances over them. It reports +// whether the copy operation was successful +func (s *String) CopyBytes(out []byte) bool { + n := len(out) + v := s.read(n) + if v == nil { + return false + } + return copy(out, v) == n +} + +// Empty reports whether the string does not contain any bytes. +func (s String) Empty() bool { + return len(s) == 0 +} diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go new file mode 100644 index 000000000..5bc246355 --- /dev/null +++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go @@ -0,0 +1,75 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation +// Function (HKDF) as defined in RFC 5869. +// +// HKDF is a cryptographic key derivation function (KDF) with the goal of +// expanding limited input keying material into one or more cryptographically +// strong secret keys. +// +// RFC 5869: https://tools.ietf.org/html/rfc5869 +package hkdf // import "golang.org/x/crypto/hkdf" + +import ( + "crypto/hmac" + "errors" + "hash" + "io" +) + +type hkdf struct { + expander hash.Hash + size int + + info []byte + counter byte + + prev []byte + cache []byte +} + +func (f *hkdf) Read(p []byte) (int, error) { + // Check whether enough data can be generated + need := len(p) + remains := len(f.cache) + int(255-f.counter+1)*f.size + if remains < need { + return 0, errors.New("hkdf: entropy limit reached") + } + // Read from the cache, if enough data is present + n := copy(p, f.cache) + p = p[n:] + + // Fill the buffer + for len(p) > 0 { + f.expander.Reset() + f.expander.Write(f.prev) + f.expander.Write(f.info) + f.expander.Write([]byte{f.counter}) + f.prev = f.expander.Sum(f.prev[:0]) + f.counter++ + + // Copy the new batch into p + f.cache = f.prev + n = copy(p, f.cache) + p = p[n:] + } + // Save leftovers for next run + f.cache = f.cache[n:] + + return need, nil +} + +// New returns a new HKDF using the given hash, the secret keying material to expand +// and optional salt and info fields. +func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { + if salt == nil { + salt = make([]byte, hash().Size()) + } + extractor := hmac.New(hash, salt) + extractor.Write(secret) + prk := extractor.Sum(nil) + + return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil} +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go new file mode 100644 index 000000000..f38797bfa --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go @@ -0,0 +1,32 @@ +// Copyright 2018 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 + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/md4/md4.go b/vendor/golang.org/x/crypto/md4/md4.go new file mode 100644 index 000000000..6d9ba9e5f --- /dev/null +++ b/vendor/golang.org/x/crypto/md4/md4.go @@ -0,0 +1,118 @@ +// 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 md4 implements the MD4 hash algorithm as defined in RFC 1320. +package md4 // import "golang.org/x/crypto/md4" + +import ( + "crypto" + "hash" +) + +func init() { + crypto.RegisterHash(crypto.MD4, New) +} + +// The size of an MD4 checksum in bytes. +const Size = 16 + +// The blocksize of MD4 in bytes. +const BlockSize = 64 + +const ( + _Chunk = 64 + _Init0 = 0x67452301 + _Init1 = 0xEFCDAB89 + _Init2 = 0x98BADCFE + _Init3 = 0x10325476 +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + s [4]uint32 + x [_Chunk]byte + nx int + len uint64 +} + +func (d *digest) Reset() { + d.s[0] = _Init0 + d.s[1] = _Init1 + d.s[2] = _Init2 + d.s[3] = _Init3 + d.nx = 0 + d.len = 0 +} + +// New returns a new hash.Hash computing the MD4 checksum. +func New() hash.Hash { + d := new(digest) + d.Reset() + return d +} + +func (d *digest) Size() int { return Size } + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + d.len += uint64(nn) + if d.nx > 0 { + n := len(p) + if n > _Chunk-d.nx { + n = _Chunk - d.nx + } + for i := 0; i < n; i++ { + d.x[d.nx+i] = p[i] + } + d.nx += n + if d.nx == _Chunk { + _Block(d, d.x[0:]) + d.nx = 0 + } + p = p[n:] + } + n := _Block(d, p) + p = p[n:] + if len(p) > 0 { + d.nx = copy(d.x[:], p) + } + return +} + +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0, so that caller can keep writing and summing. + d := new(digest) + *d = *d0 + + // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. + len := d.len + var tmp [64]byte + tmp[0] = 0x80 + if len%64 < 56 { + d.Write(tmp[0 : 56-len%64]) + } else { + d.Write(tmp[0 : 64+56-len%64]) + } + + // Length in bits. + len <<= 3 + for i := uint(0); i < 8; i++ { + tmp[i] = byte(len >> (8 * i)) + } + d.Write(tmp[0:8]) + + if d.nx != 0 { + panic("d.nx != 0") + } + + for _, s := range d.s { + in = append(in, byte(s>>0)) + in = append(in, byte(s>>8)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>24)) + } + return in +} diff --git a/vendor/golang.org/x/crypto/md4/md4block.go b/vendor/golang.org/x/crypto/md4/md4block.go new file mode 100644 index 000000000..3fed475f3 --- /dev/null +++ b/vendor/golang.org/x/crypto/md4/md4block.go @@ -0,0 +1,89 @@ +// 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. + +// MD4 block step. +// In its own file so that a faster assembly or C version +// can be substituted easily. + +package md4 + +var shift1 = []uint{3, 7, 11, 19} +var shift2 = []uint{3, 5, 9, 13} +var shift3 = []uint{3, 9, 11, 15} + +var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15} +var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15} + +func _Block(dig *digest, p []byte) int { + a := dig.s[0] + b := dig.s[1] + c := dig.s[2] + d := dig.s[3] + n := 0 + var X [16]uint32 + for len(p) >= _Chunk { + aa, bb, cc, dd := a, b, c, d + + j := 0 + for i := 0; i < 16; i++ { + X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 + j += 4 + } + + // If this needs to be made faster in the future, + // the usual trick is to unroll each of these + // loops by a factor of 4; that lets you replace + // the shift[] lookups with constants and, + // with suitable variable renaming in each + // unrolled body, delete the a, b, c, d = d, a, b, c + // (or you can let the optimizer do the renaming). + // + // The index variables are uint so that % by a power + // of two can be optimized easily by a compiler. + + // Round 1. + for i := uint(0); i < 16; i++ { + x := i + s := shift1[i%4] + f := ((c ^ d) & b) ^ d + a += f + X[x] + a = a<>(32-s) + a, b, c, d = d, a, b, c + } + + // Round 2. + for i := uint(0); i < 16; i++ { + x := xIndex2[i] + s := shift2[i%4] + g := (b & c) | (b & d) | (c & d) + a += g + X[x] + 0x5a827999 + a = a<>(32-s) + a, b, c, d = d, a, b, c + } + + // Round 3. + for i := uint(0); i < 16; i++ { + x := xIndex3[i] + s := shift3[i%4] + h := b ^ c ^ d + a += h + X[x] + 0x6ed9eba1 + a = a<>(32-s) + a, b, c, d = d, a, b, c + } + + a += aa + b += bb + c += cc + d += dd + + p = p[_Chunk:] + n += _Chunk + } + + dig.s[0] = a + dig.s[1] = b + dig.s[2] = c + dig.s[3] = d + return n +} diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go index 134654cf7..a3c021d3f 100644 --- a/vendor/golang.org/x/net/context/context.go +++ b/vendor/golang.org/x/net/context/context.go @@ -5,9 +5,11 @@ // Package context defines the Context type, which carries deadlines, // cancelation signals, and other request-scoped values across API boundaries // and between processes. +// As of Go 1.7 this package is available in the standard library under the +// name context. https://golang.org/pkg/context. // // Incoming requests to a server should create a Context, and outgoing calls to -// servers should accept a Context. The chain of function calls between must +// servers should accept a Context. The chain of function calls between must // propagate the Context, optionally replacing it with a modified copy created // using WithDeadline, WithTimeout, WithCancel, or WithValue. // @@ -16,14 +18,14 @@ // propagation: // // Do not store Contexts inside a struct type; instead, pass a Context -// explicitly to each function that needs it. The Context should be the first +// explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // // func DoSomething(ctx context.Context, arg Arg) error { // // ... use ctx ... // } // -// Do not pass a nil Context, even if a function permits it. Pass context.TODO +// Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. // // Use context Values only for request-scoped data that transits processes and @@ -36,112 +38,15 @@ // Contexts. package context // import "golang.org/x/net/context" -import "time" - -// A Context carries a deadline, a cancelation signal, and other values across -// API boundaries. -// -// Context's methods may be called by multiple goroutines simultaneously. -type Context interface { - // Deadline returns the time when work done on behalf of this context - // should be canceled. Deadline returns ok==false when no deadline is - // set. Successive calls to Deadline return the same results. - Deadline() (deadline time.Time, ok bool) - - // Done returns a channel that's closed when work done on behalf of this - // context should be canceled. Done may return nil if this context can - // never be canceled. Successive calls to Done return the same value. - // - // WithCancel arranges for Done to be closed when cancel is called; - // WithDeadline arranges for Done to be closed when the deadline - // expires; WithTimeout arranges for Done to be closed when the timeout - // elapses. - // - // Done is provided for use in select statements: - // - // // Stream generates values with DoSomething and sends them to out - // // until DoSomething returns an error or ctx.Done is closed. - // func Stream(ctx context.Context, out chan<- Value) error { - // for { - // v, err := DoSomething(ctx) - // if err != nil { - // return err - // } - // select { - // case <-ctx.Done(): - // return ctx.Err() - // case out <- v: - // } - // } - // } - // - // See http://blog.golang.org/pipelines for more examples of how to use - // a Done channel for cancelation. - Done() <-chan struct{} - - // Err returns a non-nil error value after Done is closed. Err returns - // Canceled if the context was canceled or DeadlineExceeded if the - // context's deadline passed. No other values for Err are defined. - // After Done is closed, successive calls to Err return the same value. - Err() error - - // Value returns the value associated with this context for key, or nil - // if no value is associated with key. Successive calls to Value with - // the same key returns the same result. - // - // Use context values only for request-scoped data that transits - // processes and API boundaries, not for passing optional parameters to - // functions. - // - // A key identifies a specific value in a Context. Functions that wish - // to store values in Context typically allocate a key in a global - // variable then use that key as the argument to context.WithValue and - // Context.Value. A key can be any type that supports equality; - // packages should define keys as an unexported type to avoid - // collisions. - // - // Packages that define a Context key should provide type-safe accessors - // for the values stores using that key: - // - // // Package user defines a User type that's stored in Contexts. - // package user - // - // import "golang.org/x/net/context" - // - // // User is the type of value stored in the Contexts. - // type User struct {...} - // - // // key is an unexported type for keys defined in this package. - // // This prevents collisions with keys defined in other packages. - // type key int - // - // // userKey is the key for user.User values in Contexts. It is - // // unexported; clients use user.NewContext and user.FromContext - // // instead of using this key directly. - // var userKey key = 0 - // - // // NewContext returns a new Context that carries value u. - // func NewContext(ctx context.Context, u *User) context.Context { - // return context.WithValue(ctx, userKey, u) - // } - // - // // FromContext returns the User value stored in ctx, if any. - // func FromContext(ctx context.Context) (*User, bool) { - // u, ok := ctx.Value(userKey).(*User) - // return u, ok - // } - Value(key interface{}) interface{} -} - // Background returns a non-nil, empty Context. It is never canceled, has no -// values, and has no deadline. It is typically used by the main function, +// values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming // requests. func Background() Context { return background } -// TODO returns a non-nil, empty Context. Code should use context.TODO when +// TODO returns a non-nil, empty Context. Code should use context.TODO when // it's unclear which Context to use or it is not yet available (because the // surrounding function has not yet been extended to accept a Context // parameter). TODO is recognized by static analysis tools that determine @@ -149,8 +54,3 @@ func Background() Context { func TODO() Context { return todo } - -// A CancelFunc tells an operation to abandon its work. -// A CancelFunc does not wait for the work to stop. -// After the first call, subsequent calls to a CancelFunc do nothing. -type CancelFunc func() diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go index f8cda19ad..d20f52b7d 100644 --- a/vendor/golang.org/x/net/context/go17.go +++ b/vendor/golang.org/x/net/context/go17.go @@ -35,8 +35,8 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { } // WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go new file mode 100644 index 000000000..d88bd1db1 --- /dev/null +++ b/vendor/golang.org/x/net/context/go19.go @@ -0,0 +1,20 @@ +// Copyright 2017 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 go1.9 + +package context + +import "context" // standard library's context, as of Go 1.7 + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context = context.Context + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc = context.CancelFunc diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go index 5a30acabd..0f35592df 100644 --- a/vendor/golang.org/x/net/context/pre_go17.go +++ b/vendor/golang.org/x/net/context/pre_go17.go @@ -13,7 +13,7 @@ import ( "time" ) -// An emptyCtx is never canceled, has no values, and has no deadline. It is not +// An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. type emptyCtx int @@ -104,7 +104,7 @@ func propagateCancel(parent Context, child canceler) { } // parentCancelCtx follows a chain of parent references until it finds a -// *cancelCtx. This function understands how each of the concrete types in this +// *cancelCtx. This function understands how each of the concrete types in this // package represents its parent. func parentCancelCtx(parent Context) (*cancelCtx, bool) { for { @@ -134,14 +134,14 @@ func removeChild(parent Context, child canceler) { p.mu.Unlock() } -// A canceler is a context type that can be canceled directly. The +// A canceler is a context type that can be canceled directly. The // implementations are *cancelCtx and *timerCtx. type canceler interface { cancel(removeFromParent bool, err error) Done() <-chan struct{} } -// A cancelCtx can be canceled. When canceled, it also cancels any children +// A cancelCtx can be canceled. When canceled, it also cancels any children // that implement canceler. type cancelCtx struct { Context @@ -193,8 +193,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) { } // WithDeadline returns a copy of the parent context with the deadline adjusted -// to be no later than d. If the parent's deadline is already earlier than d, -// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. @@ -226,8 +226,8 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { return c, func() { c.cancel(true, Canceled) } } -// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to -// implement Done and Err. It implements cancel by stopping its timer then +// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to +// implement Done and Err. It implements cancel by stopping its timer then // delegating to cancelCtx.cancel. type timerCtx struct { *cancelCtx @@ -281,7 +281,7 @@ func WithValue(parent Context, key interface{}, val interface{}) Context { return &valueCtx{parent, key, val} } -// A valueCtx carries a key-value pair. It implements Value for that key and +// A valueCtx carries a key-value pair. It implements Value for that key and // delegates all other calls to the embedded Context. type valueCtx struct { Context diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go new file mode 100644 index 000000000..b105f80be --- /dev/null +++ b/vendor/golang.org/x/net/context/pre_go19.go @@ -0,0 +1,109 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.9 + +package context + +import "time" + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context interface { + // Deadline returns the time when work done on behalf of this context + // should be canceled. Deadline returns ok==false when no deadline is + // set. Successive calls to Deadline return the same results. + Deadline() (deadline time.Time, ok bool) + + // Done returns a channel that's closed when work done on behalf of this + // context should be canceled. Done may return nil if this context can + // never be canceled. Successive calls to Done return the same value. + // + // WithCancel arranges for Done to be closed when cancel is called; + // WithDeadline arranges for Done to be closed when the deadline + // expires; WithTimeout arranges for Done to be closed when the timeout + // elapses. + // + // Done is provided for use in select statements: + // + // // Stream generates values with DoSomething and sends them to out + // // until DoSomething returns an error or ctx.Done is closed. + // func Stream(ctx context.Context, out chan<- Value) error { + // for { + // v, err := DoSomething(ctx) + // if err != nil { + // return err + // } + // select { + // case <-ctx.Done(): + // return ctx.Err() + // case out <- v: + // } + // } + // } + // + // See http://blog.golang.org/pipelines for more examples of how to use + // a Done channel for cancelation. + Done() <-chan struct{} + + // Err returns a non-nil error value after Done is closed. Err returns + // Canceled if the context was canceled or DeadlineExceeded if the + // context's deadline passed. No other values for Err are defined. + // After Done is closed, successive calls to Err return the same value. + Err() error + + // Value returns the value associated with this context for key, or nil + // if no value is associated with key. Successive calls to Value with + // the same key returns the same result. + // + // Use context values only for request-scoped data that transits + // processes and API boundaries, not for passing optional parameters to + // functions. + // + // A key identifies a specific value in a Context. Functions that wish + // to store values in Context typically allocate a key in a global + // variable then use that key as the argument to context.WithValue and + // Context.Value. A key can be any type that supports equality; + // packages should define keys as an unexported type to avoid + // collisions. + // + // Packages that define a Context key should provide type-safe accessors + // for the values stores using that key: + // + // // Package user defines a User type that's stored in Contexts. + // package user + // + // import "golang.org/x/net/context" + // + // // User is the type of value stored in the Contexts. + // type User struct {...} + // + // // key is an unexported type for keys defined in this package. + // // This prevents collisions with keys defined in other packages. + // type key int + // + // // userKey is the key for user.User values in Contexts. It is + // // unexported; clients use user.NewContext and user.FromContext + // // instead of using this key directly. + // var userKey key = 0 + // + // // NewContext returns a new Context that carries value u. + // func NewContext(ctx context.Context, u *User) context.Context { + // return context.WithValue(ctx, userKey, u) + // } + // + // // FromContext returns the User value stored in ctx, if any. + // func FromContext(ctx context.Context) (*User, bool) { + // u, ok := ctx.Value(userKey).(*User) + // return u, ok + // } + Value(key interface{}) interface{} +} + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc func() diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 000000000..3d88f8667 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,38 @@ +// Copyright 2018 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 cpu implements processor feature detection for +// various CPU architectures. +package cpu + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 000000000..d93036f75 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 cpu + +const cacheLineSize = 32 diff --git a/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/golang.org/x/sys/cpu/cpu_arm64.go new file mode 100644 index 000000000..1d2ab2902 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 cpu + +const cacheLineSize = 64 diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 000000000..f7cb46971 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,16 @@ +// Copyright 2018 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 386 amd64 amd64p32 +// +build !gccgo + +package cpu + +// cpuid is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo.c b/vendor/golang.org/x/sys/cpu/cpu_gccgo.c new file mode 100644 index 000000000..e363c7d13 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo.c @@ -0,0 +1,43 @@ +// Copyright 2018 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 386 amd64 amd64p32 +// +build gccgo + +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +// +// TODO: Replace with a better alternative: +// +// #include +// +// #pragma GCC target("xsave") +// +// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) { +// unsigned long long x = _xgetbv(0); +// *eax = x & 0xffffffff; +// *edx = (x >> 32) & 0xffffffff; +// } +// +// Note that _xgetbv is defined starting with GCC 8. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + __asm(" xorl %%ecx, %%ecx\n" + " xgetbv" + : "=a"(*eax), "=d"(*edx)); +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_gccgo.go b/vendor/golang.org/x/sys/cpu/cpu_gccgo.go new file mode 100644 index 000000000..ba49b91bd --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_gccgo.go @@ -0,0 +1,26 @@ +// Copyright 2018 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 386 amd64 amd64p32 +// +build gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} diff --git a/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 000000000..6165f1212 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,9 @@ +// Copyright 2018 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 mips64 mips64le + +package cpu + +const cacheLineSize = 32 diff --git a/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 000000000..1269eee88 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,9 @@ +// Copyright 2018 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 mips mipsle + +package cpu + +const cacheLineSize = 32 diff --git a/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go new file mode 100644 index 000000000..d10759a52 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go @@ -0,0 +1,9 @@ +// Copyright 2018 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 ppc64 ppc64le + +package cpu + +const cacheLineSize = 128 diff --git a/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/golang.org/x/sys/cpu/cpu_s390x.go new file mode 100644 index 000000000..684c4f005 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_s390x.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 cpu + +const cacheLineSize = 256 diff --git a/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 000000000..71e288b06 --- /dev/null +++ b/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,55 @@ +// Copyright 2018 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 386 amd64 amd64p32 + +package cpu + +const cacheLineSize = 64 + +func init() { + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + + osSupportsAVX := false + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + _, ebx7, _, _ := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasADX = isSet(19, ebx7) +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1< 0 +// +func (x *Dec) Sign() int { + return x.UnscaledBig().Sign() +} + +// Neg sets z to -x and returns z. +func (z *Dec) Neg(x *Dec) *Dec { + z.SetScale(x.Scale()) + z.UnscaledBig().Neg(x.UnscaledBig()) + return z +} + +// Cmp compares x and y and returns: +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +// +func (x *Dec) Cmp(y *Dec) int { + xx, yy := upscale(x, y) + return xx.UnscaledBig().Cmp(yy.UnscaledBig()) +} + +// Abs sets z to |x| (the absolute value of x) and returns z. +func (z *Dec) Abs(x *Dec) *Dec { + z.SetScale(x.Scale()) + z.UnscaledBig().Abs(x.UnscaledBig()) + return z +} + +// Add sets z to the sum x+y and returns z. +// The scale of z is the greater of the scales of x and y. +func (z *Dec) Add(x, y *Dec) *Dec { + xx, yy := upscale(x, y) + z.SetScale(xx.Scale()) + z.UnscaledBig().Add(xx.UnscaledBig(), yy.UnscaledBig()) + return z +} + +// Sub sets z to the difference x-y and returns z. +// The scale of z is the greater of the scales of x and y. +func (z *Dec) Sub(x, y *Dec) *Dec { + xx, yy := upscale(x, y) + z.SetScale(xx.Scale()) + z.UnscaledBig().Sub(xx.UnscaledBig(), yy.UnscaledBig()) + return z +} + +// Mul sets z to the product x*y and returns z. +// The scale of z is the sum of the scales of x and y. +func (z *Dec) Mul(x, y *Dec) *Dec { + z.SetScale(x.Scale() + y.Scale()) + z.UnscaledBig().Mul(x.UnscaledBig(), y.UnscaledBig()) + return z +} + +// Round sets z to the value of x rounded to Scale s using Rounder r, and +// returns z. +func (z *Dec) Round(x *Dec, s Scale, r Rounder) *Dec { + return z.QuoRound(x, NewDec(1, 0), s, r) +} + +// QuoRound sets z to the quotient x/y, rounded using the given Rounder to the +// specified scale. +// +// If the rounder is RoundExact but the result can not be expressed exactly at +// the specified scale, QuoRound returns nil, and the value of z is undefined. +// +// There is no corresponding Div method; the equivalent can be achieved through +// the choice of Rounder used. +// +func (z *Dec) QuoRound(x, y *Dec, s Scale, r Rounder) *Dec { + return z.quo(x, y, sclr{s}, r) +} + +func (z *Dec) quo(x, y *Dec, s scaler, r Rounder) *Dec { + scl := s.Scale(x, y) + var zzz *Dec + if r.UseRemainder() { + zz, rA, rB := new(Dec).quoRem(x, y, scl, true, new(big.Int), new(big.Int)) + zzz = r.Round(new(Dec), zz, rA, rB) + } else { + zz, _, _ := new(Dec).quoRem(x, y, scl, false, nil, nil) + zzz = r.Round(new(Dec), zz, nil, nil) + } + if zzz == nil { + return nil + } + return z.Set(zzz) +} + +// QuoExact sets z to the quotient x/y and returns z when x/y is a finite +// decimal. Otherwise it returns nil and the value of z is undefined. +// +// The scale of a non-nil result is "x.Scale() - y.Scale()" or greater; it is +// calculated so that the remainder will be zero whenever x/y is a finite +// decimal. +func (z *Dec) QuoExact(x, y *Dec) *Dec { + return z.quo(x, y, scaleQuoExact{}, RoundExact) +} + +// quoRem sets z to the quotient x/y with the scale s, and if useRem is true, +// it sets remNum and remDen to the numerator and denominator of the remainder. +// It returns z, remNum and remDen. +// +// The remainder is normalized to the range -1 < r < 1 to simplify rounding; +// that is, the results satisfy the following equation: +// +// x / y = z + (remNum/remDen) * 10**(-z.Scale()) +// +// See Rounder for more details about rounding. +// +func (z *Dec) quoRem(x, y *Dec, s Scale, useRem bool, + remNum, remDen *big.Int) (*Dec, *big.Int, *big.Int) { + // difference (required adjustment) compared to "canonical" result scale + shift := s - (x.Scale() - y.Scale()) + // pointers to adjusted unscaled dividend and divisor + var ix, iy *big.Int + switch { + case shift > 0: + // increased scale: decimal-shift dividend left + ix = new(big.Int).Mul(x.UnscaledBig(), exp10(shift)) + iy = y.UnscaledBig() + case shift < 0: + // decreased scale: decimal-shift divisor left + ix = x.UnscaledBig() + iy = new(big.Int).Mul(y.UnscaledBig(), exp10(-shift)) + default: + ix = x.UnscaledBig() + iy = y.UnscaledBig() + } + // save a copy of iy in case it to be overwritten with the result + iy2 := iy + if iy == z.UnscaledBig() { + iy2 = new(big.Int).Set(iy) + } + // set scale + z.SetScale(s) + // set unscaled + if useRem { + // Int division + _, intr := z.UnscaledBig().QuoRem(ix, iy, new(big.Int)) + // set remainder + remNum.Set(intr) + remDen.Set(iy2) + } else { + z.UnscaledBig().Quo(ix, iy) + } + return z, remNum, remDen +} + +type sclr struct{ s Scale } + +func (s sclr) Scale(x, y *Dec) Scale { + return s.s +} + +type scaleQuoExact struct{} + +func (sqe scaleQuoExact) Scale(x, y *Dec) Scale { + rem := new(big.Rat).SetFrac(x.UnscaledBig(), y.UnscaledBig()) + f2, f5 := factor2(rem.Denom()), factor(rem.Denom(), bigInt[5]) + var f10 Scale + if f2 > f5 { + f10 = Scale(f2) + } else { + f10 = Scale(f5) + } + return x.Scale() - y.Scale() + f10 +} + +func factor(n *big.Int, p *big.Int) int { + // could be improved for large factors + d, f := n, 0 + for { + dd, dm := new(big.Int).DivMod(d, p, new(big.Int)) + if dm.Sign() == 0 { + f++ + d = dd + } else { + break + } + } + return f +} + +func factor2(n *big.Int) int { + // could be improved for large factors + f := 0 + for ; n.Bit(f) == 0; f++ { + } + return f +} + +func upscale(a, b *Dec) (*Dec, *Dec) { + if a.Scale() == b.Scale() { + return a, b + } + if a.Scale() > b.Scale() { + bb := b.rescale(a.Scale()) + return a, bb + } + aa := a.rescale(b.Scale()) + return aa, b +} + +func exp10(x Scale) *big.Int { + if int(x) < len(exp10cache) { + return &exp10cache[int(x)] + } + return new(big.Int).Exp(bigInt[10], big.NewInt(int64(x)), nil) +} + +func (x *Dec) rescale(newScale Scale) *Dec { + shift := newScale - x.Scale() + switch { + case shift < 0: + e := exp10(-shift) + return NewDecBig(new(big.Int).Quo(x.UnscaledBig(), e), newScale) + case shift > 0: + e := exp10(shift) + return NewDecBig(new(big.Int).Mul(x.UnscaledBig(), e), newScale) + } + return x +} + +var zeros = []byte("00000000000000000000000000000000" + + "00000000000000000000000000000000") +var lzeros = Scale(len(zeros)) + +func appendZeros(s []byte, n Scale) []byte { + for i := Scale(0); i < n; i += lzeros { + if n > i+lzeros { + s = append(s, zeros...) + } else { + s = append(s, zeros[0:n-i]...) + } + } + return s +} + +func (x *Dec) String() string { + if x == nil { + return "" + } + scale := x.Scale() + s := []byte(x.UnscaledBig().String()) + if scale <= 0 { + if scale != 0 && x.unscaled.Sign() != 0 { + s = appendZeros(s, -scale) + } + return string(s) + } + negbit := Scale(-((x.Sign() - 1) / 2)) + // scale > 0 + lens := Scale(len(s)) + if lens-negbit <= scale { + ss := make([]byte, 0, scale+2) + if negbit == 1 { + ss = append(ss, '-') + } + ss = append(ss, '0', '.') + ss = appendZeros(ss, scale-lens+negbit) + ss = append(ss, s[negbit:]...) + return string(ss) + } + // lens > scale + ss := make([]byte, 0, lens+1) + ss = append(ss, s[:lens-scale]...) + ss = append(ss, '.') + ss = append(ss, s[lens-scale:]...) + return string(ss) +} + +// Format is a support routine for fmt.Formatter. It accepts the decimal +// formats 'd' and 'f', and handles both equivalently. +// Width, precision, flags and bases 2, 8, 16 are not supported. +func (x *Dec) Format(s fmt.State, ch rune) { + if ch != 'd' && ch != 'f' && ch != 'v' && ch != 's' { + fmt.Fprintf(s, "%%!%c(dec.Dec=%s)", ch, x.String()) + return + } + fmt.Fprintf(s, x.String()) +} + +func (z *Dec) scan(r io.RuneScanner) (*Dec, error) { + unscaled := make([]byte, 0, 256) // collects chars of unscaled as bytes + dp, dg := -1, -1 // indexes of decimal point, first digit +loop: + for { + ch, _, err := r.ReadRune() + if err == io.EOF { + break loop + } + if err != nil { + return nil, err + } + switch { + case ch == '+' || ch == '-': + if len(unscaled) > 0 || dp >= 0 { // must be first character + r.UnreadRune() + break loop + } + case ch == '.': + if dp >= 0 { + r.UnreadRune() + break loop + } + dp = len(unscaled) + continue // don't add to unscaled + case ch >= '0' && ch <= '9': + if dg == -1 { + dg = len(unscaled) + } + default: + r.UnreadRune() + break loop + } + unscaled = append(unscaled, byte(ch)) + } + if dg == -1 { + return nil, fmt.Errorf("no digits read") + } + if dp >= 0 { + z.SetScale(Scale(len(unscaled) - dp)) + } else { + z.SetScale(0) + } + _, ok := z.UnscaledBig().SetString(string(unscaled), 10) + if !ok { + return nil, fmt.Errorf("invalid decimal: %s", string(unscaled)) + } + return z, nil +} + +// SetString sets z to the value of s, interpreted as a decimal (base 10), +// and returns z and a boolean indicating success. The scale of z is the +// number of digits after the decimal point (including any trailing 0s), +// or 0 if there is no decimal point. If SetString fails, the value of z +// is undefined but the returned value is nil. +func (z *Dec) SetString(s string) (*Dec, bool) { + r := strings.NewReader(s) + _, err := z.scan(r) + if err != nil { + return nil, false + } + _, _, err = r.ReadRune() + if err != io.EOF { + return nil, false + } + // err == io.EOF => scan consumed all of s + return z, true +} + +// Scan is a support routine for fmt.Scanner; it sets z to the value of +// the scanned number. It accepts the decimal formats 'd' and 'f', and +// handles both equivalently. Bases 2, 8, 16 are not supported. +// The scale of z is the number of digits after the decimal point +// (including any trailing 0s), or 0 if there is no decimal point. +func (z *Dec) Scan(s fmt.ScanState, ch rune) error { + if ch != 'd' && ch != 'f' && ch != 's' && ch != 'v' { + return fmt.Errorf("Dec.Scan: invalid verb '%c'", ch) + } + s.SkipSpace() + _, err := z.scan(s) + return err +} + +// Gob encoding version +const decGobVersion byte = 1 + +func scaleBytes(s Scale) []byte { + buf := make([]byte, scaleSize) + i := scaleSize + for j := 0; j < scaleSize; j++ { + i-- + buf[i] = byte(s) + s >>= 8 + } + return buf +} + +func scale(b []byte) (s Scale) { + for j := 0; j < scaleSize; j++ { + s <<= 8 + s |= Scale(b[j]) + } + return +} + +// GobEncode implements the gob.GobEncoder interface. +func (x *Dec) GobEncode() ([]byte, error) { + buf, err := x.UnscaledBig().GobEncode() + if err != nil { + return nil, err + } + buf = append(append(buf, scaleBytes(x.Scale())...), decGobVersion) + return buf, nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Dec) GobDecode(buf []byte) error { + if len(buf) == 0 { + return fmt.Errorf("Dec.GobDecode: no data") + } + b := buf[len(buf)-1] + if b != decGobVersion { + return fmt.Errorf("Dec.GobDecode: encoding version %d not supported", b) + } + l := len(buf) - scaleSize - 1 + err := z.UnscaledBig().GobDecode(buf[:l]) + if err != nil { + return err + } + z.SetScale(scale(buf[l : l+scaleSize])) + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (x *Dec) MarshalText() ([]byte, error) { + return []byte(x.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (z *Dec) UnmarshalText(data []byte) error { + _, ok := z.SetString(string(data)) + if !ok { + return fmt.Errorf("invalid inf.Dec") + } + return nil +} diff --git a/vendor/gopkg.in/inf.v0/rounder.go b/vendor/gopkg.in/inf.v0/rounder.go new file mode 100644 index 000000000..3a97ef529 --- /dev/null +++ b/vendor/gopkg.in/inf.v0/rounder.go @@ -0,0 +1,145 @@ +package inf + +import ( + "math/big" +) + +// Rounder represents a method for rounding the (possibly infinite decimal) +// result of a division to a finite Dec. It is used by Dec.Round() and +// Dec.Quo(). +// +// See the Example for results of using each Rounder with some sample values. +// +type Rounder rounder + +// See http://speleotrove.com/decimal/damodel.html#refround for more detailed +// definitions of these rounding modes. +var ( + RoundDown Rounder // towards 0 + RoundUp Rounder // away from 0 + RoundFloor Rounder // towards -infinity + RoundCeil Rounder // towards +infinity + RoundHalfDown Rounder // to nearest; towards 0 if same distance + RoundHalfUp Rounder // to nearest; away from 0 if same distance + RoundHalfEven Rounder // to nearest; even last digit if same distance +) + +// RoundExact is to be used in the case when rounding is not necessary. +// When used with Quo or Round, it returns the result verbatim when it can be +// expressed exactly with the given precision, and it returns nil otherwise. +// QuoExact is a shorthand for using Quo with RoundExact. +var RoundExact Rounder + +type rounder interface { + + // When UseRemainder() returns true, the Round() method is passed the + // remainder of the division, expressed as the numerator and denominator of + // a rational. + UseRemainder() bool + + // Round sets the rounded value of a quotient to z, and returns z. + // quo is rounded down (truncated towards zero) to the scale obtained from + // the Scaler in Quo(). + // + // When the remainder is not used, remNum and remDen are nil. + // When used, the remainder is normalized between -1 and 1; that is: + // + // -|remDen| < remNum < |remDen| + // + // remDen has the same sign as y, and remNum is zero or has the same sign + // as x. + Round(z, quo *Dec, remNum, remDen *big.Int) *Dec +} + +type rndr struct { + useRem bool + round func(z, quo *Dec, remNum, remDen *big.Int) *Dec +} + +func (r rndr) UseRemainder() bool { + return r.useRem +} + +func (r rndr) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec { + return r.round(z, quo, remNum, remDen) +} + +var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)} + +func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec { + return func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + brA, brB := rA.BitLen(), rB.BitLen() + if brA < brB-1 { + // brA < brB-1 => |rA| < |rB/2| + return z + } + roundUp := false + srA, srB := rA.Sign(), rB.Sign() + s := srA * srB + if brA == brB-1 { + rA2 := new(big.Int).Lsh(rA, 1) + if s < 0 { + rA2.Neg(rA2) + } + roundUp = f(rA2.Cmp(rB)*srB, z.UnscaledBig().Bit(0)) + } else { + // brA > brB-1 => |rA| > |rB/2| + roundUp = true + } + if roundUp { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[s+1]) + } + return z + } +} + +func init() { + RoundExact = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + if rA.Sign() != 0 { + return nil + } + return z.Set(q) + }} + RoundDown = rndr{false, + func(z, q *Dec, rA, rB *big.Int) *Dec { + return z.Set(q) + }} + RoundUp = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + if rA.Sign() != 0 { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1]) + } + return z + }} + RoundFloor = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + if rA.Sign()*rB.Sign() < 0 { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[0]) + } + return z + }} + RoundCeil = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + if rA.Sign()*rB.Sign() > 0 { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[2]) + } + return z + }} + RoundHalfDown = rndr{true, roundHalf( + func(c int, odd uint) bool { + return c > 0 + })} + RoundHalfUp = rndr{true, roundHalf( + func(c int, odd uint) bool { + return c >= 0 + })} + RoundHalfEven = rndr{true, roundHalf( + func(c int, odd uint) bool { + return c > 0 || c == 0 && odd == 1 + })} +} diff --git a/vendor/gopkg.in/mgo.v2/LICENSE b/vendor/gopkg.in/mgo.v2/LICENSE new file mode 100644 index 000000000..770c7672b --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/LICENSE @@ -0,0 +1,25 @@ +mgo - MongoDB driver for Go + +Copyright (c) 2010-2013 - Gustavo Niemeyer + +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. + +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/gopkg.in/mgo.v2/Makefile b/vendor/gopkg.in/mgo.v2/Makefile new file mode 100644 index 000000000..d1027d450 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/Makefile @@ -0,0 +1,5 @@ +startdb: + @harness/setup.sh start + +stopdb: + @harness/setup.sh stop diff --git a/vendor/gopkg.in/mgo.v2/README.md b/vendor/gopkg.in/mgo.v2/README.md new file mode 100644 index 000000000..f4e452c04 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/README.md @@ -0,0 +1,4 @@ +The MongoDB driver for Go +------------------------- + +Please go to [http://labix.org/mgo](http://labix.org/mgo) for all project details. diff --git a/vendor/gopkg.in/mgo.v2/auth.go b/vendor/gopkg.in/mgo.v2/auth.go new file mode 100644 index 000000000..dc26e52f5 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/auth.go @@ -0,0 +1,467 @@ +// mgo - MongoDB driver for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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 mgo + +import ( + "crypto/md5" + "crypto/sha1" + "encoding/hex" + "errors" + "fmt" + "sync" + + "gopkg.in/mgo.v2/bson" + "gopkg.in/mgo.v2/internal/scram" +) + +type authCmd struct { + Authenticate int + + Nonce string + User string + Key string +} + +type startSaslCmd struct { + StartSASL int `bson:"startSasl"` +} + +type authResult struct { + ErrMsg string + Ok bool +} + +type getNonceCmd struct { + GetNonce int +} + +type getNonceResult struct { + Nonce string + Err string "$err" + Code int +} + +type logoutCmd struct { + Logout int +} + +type saslCmd struct { + Start int `bson:"saslStart,omitempty"` + Continue int `bson:"saslContinue,omitempty"` + ConversationId int `bson:"conversationId,omitempty"` + Mechanism string `bson:"mechanism,omitempty"` + Payload []byte +} + +type saslResult struct { + Ok bool `bson:"ok"` + NotOk bool `bson:"code"` // Server <= 2.3.2 returns ok=1 & code>0 on errors (WTF?) + Done bool + + ConversationId int `bson:"conversationId"` + Payload []byte + ErrMsg string +} + +type saslStepper interface { + Step(serverData []byte) (clientData []byte, done bool, err error) + Close() +} + +func (socket *mongoSocket) getNonce() (nonce string, err error) { + socket.Lock() + for socket.cachedNonce == "" && socket.dead == nil { + debugf("Socket %p to %s: waiting for nonce", socket, socket.addr) + socket.gotNonce.Wait() + } + if socket.cachedNonce == "mongos" { + socket.Unlock() + return "", errors.New("Can't authenticate with mongos; see http://j.mp/mongos-auth") + } + debugf("Socket %p to %s: got nonce", socket, socket.addr) + nonce, err = socket.cachedNonce, socket.dead + socket.cachedNonce = "" + socket.Unlock() + if err != nil { + nonce = "" + } + return +} + +func (socket *mongoSocket) resetNonce() { + debugf("Socket %p to %s: requesting a new nonce", socket, socket.addr) + op := &queryOp{} + op.query = &getNonceCmd{GetNonce: 1} + op.collection = "admin.$cmd" + op.limit = -1 + op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) { + if err != nil { + socket.kill(errors.New("getNonce: "+err.Error()), true) + return + } + result := &getNonceResult{} + err = bson.Unmarshal(docData, &result) + if err != nil { + socket.kill(errors.New("Failed to unmarshal nonce: "+err.Error()), true) + return + } + debugf("Socket %p to %s: nonce unmarshalled: %#v", socket, socket.addr, result) + if result.Code == 13390 { + // mongos doesn't yet support auth (see http://j.mp/mongos-auth) + result.Nonce = "mongos" + } else if result.Nonce == "" { + var msg string + if result.Err != "" { + msg = fmt.Sprintf("Got an empty nonce: %s (%d)", result.Err, result.Code) + } else { + msg = "Got an empty nonce" + } + socket.kill(errors.New(msg), true) + return + } + socket.Lock() + if socket.cachedNonce != "" { + socket.Unlock() + panic("resetNonce: nonce already cached") + } + socket.cachedNonce = result.Nonce + socket.gotNonce.Signal() + socket.Unlock() + } + err := socket.Query(op) + if err != nil { + socket.kill(errors.New("resetNonce: "+err.Error()), true) + } +} + +func (socket *mongoSocket) Login(cred Credential) error { + socket.Lock() + if cred.Mechanism == "" && socket.serverInfo.MaxWireVersion >= 3 { + cred.Mechanism = "SCRAM-SHA-1" + } + for _, sockCred := range socket.creds { + if sockCred == cred { + debugf("Socket %p to %s: login: db=%q user=%q (already logged in)", socket, socket.addr, cred.Source, cred.Username) + socket.Unlock() + return nil + } + } + if socket.dropLogout(cred) { + debugf("Socket %p to %s: login: db=%q user=%q (cached)", socket, socket.addr, cred.Source, cred.Username) + socket.creds = append(socket.creds, cred) + socket.Unlock() + return nil + } + socket.Unlock() + + debugf("Socket %p to %s: login: db=%q user=%q", socket, socket.addr, cred.Source, cred.Username) + + var err error + switch cred.Mechanism { + case "", "MONGODB-CR", "MONGO-CR": // Name changed to MONGODB-CR in SERVER-8501. + err = socket.loginClassic(cred) + case "PLAIN": + err = socket.loginPlain(cred) + case "MONGODB-X509": + err = socket.loginX509(cred) + default: + // Try SASL for everything else, if it is available. + err = socket.loginSASL(cred) + } + + if err != nil { + debugf("Socket %p to %s: login error: %s", socket, socket.addr, err) + } else { + debugf("Socket %p to %s: login successful", socket, socket.addr) + } + return err +} + +func (socket *mongoSocket) loginClassic(cred Credential) error { + // Note that this only works properly because this function is + // synchronous, which means the nonce won't get reset while we're + // using it and any other login requests will block waiting for a + // new nonce provided in the defer call below. + nonce, err := socket.getNonce() + if err != nil { + return err + } + defer socket.resetNonce() + + psum := md5.New() + psum.Write([]byte(cred.Username + ":mongo:" + cred.Password)) + + ksum := md5.New() + ksum.Write([]byte(nonce + cred.Username)) + ksum.Write([]byte(hex.EncodeToString(psum.Sum(nil)))) + + key := hex.EncodeToString(ksum.Sum(nil)) + + cmd := authCmd{Authenticate: 1, User: cred.Username, Nonce: nonce, Key: key} + res := authResult{} + return socket.loginRun(cred.Source, &cmd, &res, func() error { + if !res.Ok { + return errors.New(res.ErrMsg) + } + socket.Lock() + socket.dropAuth(cred.Source) + socket.creds = append(socket.creds, cred) + socket.Unlock() + return nil + }) +} + +type authX509Cmd struct { + Authenticate int + User string + Mechanism string +} + +func (socket *mongoSocket) loginX509(cred Credential) error { + cmd := authX509Cmd{Authenticate: 1, User: cred.Username, Mechanism: "MONGODB-X509"} + res := authResult{} + return socket.loginRun(cred.Source, &cmd, &res, func() error { + if !res.Ok { + return errors.New(res.ErrMsg) + } + socket.Lock() + socket.dropAuth(cred.Source) + socket.creds = append(socket.creds, cred) + socket.Unlock() + return nil + }) +} + +func (socket *mongoSocket) loginPlain(cred Credential) error { + cmd := saslCmd{Start: 1, Mechanism: "PLAIN", Payload: []byte("\x00" + cred.Username + "\x00" + cred.Password)} + res := authResult{} + return socket.loginRun(cred.Source, &cmd, &res, func() error { + if !res.Ok { + return errors.New(res.ErrMsg) + } + socket.Lock() + socket.dropAuth(cred.Source) + socket.creds = append(socket.creds, cred) + socket.Unlock() + return nil + }) +} + +func (socket *mongoSocket) loginSASL(cred Credential) error { + var sasl saslStepper + var err error + if cred.Mechanism == "SCRAM-SHA-1" { + // SCRAM is handled without external libraries. + sasl = saslNewScram(cred) + } else if len(cred.ServiceHost) > 0 { + sasl, err = saslNew(cred, cred.ServiceHost) + } else { + sasl, err = saslNew(cred, socket.Server().Addr) + } + if err != nil { + return err + } + defer sasl.Close() + + // The goal of this logic is to carry a locked socket until the + // local SASL step confirms the auth is valid; the socket needs to be + // locked so that concurrent action doesn't leave the socket in an + // auth state that doesn't reflect the operations that took place. + // As a simple case, imagine inverting login=>logout to logout=>login. + // + // The logic below works because the lock func isn't called concurrently. + locked := false + lock := func(b bool) { + if locked != b { + locked = b + if b { + socket.Lock() + } else { + socket.Unlock() + } + } + } + + lock(true) + defer lock(false) + + start := 1 + cmd := saslCmd{} + res := saslResult{} + for { + payload, done, err := sasl.Step(res.Payload) + if err != nil { + return err + } + if done && res.Done { + socket.dropAuth(cred.Source) + socket.creds = append(socket.creds, cred) + break + } + lock(false) + + cmd = saslCmd{ + Start: start, + Continue: 1 - start, + ConversationId: res.ConversationId, + Mechanism: cred.Mechanism, + Payload: payload, + } + start = 0 + err = socket.loginRun(cred.Source, &cmd, &res, func() error { + // See the comment on lock for why this is necessary. + lock(true) + if !res.Ok || res.NotOk { + return fmt.Errorf("server returned error on SASL authentication step: %s", res.ErrMsg) + } + return nil + }) + if err != nil { + return err + } + if done && res.Done { + socket.dropAuth(cred.Source) + socket.creds = append(socket.creds, cred) + break + } + } + + return nil +} + +func saslNewScram(cred Credential) *saslScram { + credsum := md5.New() + credsum.Write([]byte(cred.Username + ":mongo:" + cred.Password)) + client := scram.NewClient(sha1.New, cred.Username, hex.EncodeToString(credsum.Sum(nil))) + return &saslScram{cred: cred, client: client} +} + +type saslScram struct { + cred Credential + client *scram.Client +} + +func (s *saslScram) Close() {} + +func (s *saslScram) Step(serverData []byte) (clientData []byte, done bool, err error) { + more := s.client.Step(serverData) + return s.client.Out(), !more, s.client.Err() +} + +func (socket *mongoSocket) loginRun(db string, query, result interface{}, f func() error) error { + var mutex sync.Mutex + var replyErr error + mutex.Lock() + + op := queryOp{} + op.query = query + op.collection = db + ".$cmd" + op.limit = -1 + op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) { + defer mutex.Unlock() + + if err != nil { + replyErr = err + return + } + + err = bson.Unmarshal(docData, result) + if err != nil { + replyErr = err + } else { + // Must handle this within the read loop for the socket, so + // that concurrent login requests are properly ordered. + replyErr = f() + } + } + + err := socket.Query(&op) + if err != nil { + return err + } + mutex.Lock() // Wait. + return replyErr +} + +func (socket *mongoSocket) Logout(db string) { + socket.Lock() + cred, found := socket.dropAuth(db) + if found { + debugf("Socket %p to %s: logout: db=%q (flagged)", socket, socket.addr, db) + socket.logout = append(socket.logout, cred) + } + socket.Unlock() +} + +func (socket *mongoSocket) LogoutAll() { + socket.Lock() + if l := len(socket.creds); l > 0 { + debugf("Socket %p to %s: logout all (flagged %d)", socket, socket.addr, l) + socket.logout = append(socket.logout, socket.creds...) + socket.creds = socket.creds[0:0] + } + socket.Unlock() +} + +func (socket *mongoSocket) flushLogout() (ops []interface{}) { + socket.Lock() + if l := len(socket.logout); l > 0 { + debugf("Socket %p to %s: logout all (flushing %d)", socket, socket.addr, l) + for i := 0; i != l; i++ { + op := queryOp{} + op.query = &logoutCmd{1} + op.collection = socket.logout[i].Source + ".$cmd" + op.limit = -1 + ops = append(ops, &op) + } + socket.logout = socket.logout[0:0] + } + socket.Unlock() + return +} + +func (socket *mongoSocket) dropAuth(db string) (cred Credential, found bool) { + for i, sockCred := range socket.creds { + if sockCred.Source == db { + copy(socket.creds[i:], socket.creds[i+1:]) + socket.creds = socket.creds[:len(socket.creds)-1] + return sockCred, true + } + } + return cred, false +} + +func (socket *mongoSocket) dropLogout(cred Credential) (found bool) { + for i, sockCred := range socket.logout { + if sockCred == cred { + copy(socket.logout[i:], socket.logout[i+1:]) + socket.logout = socket.logout[:len(socket.logout)-1] + return true + } + } + return false +} diff --git a/vendor/gopkg.in/mgo.v2/bson/LICENSE b/vendor/gopkg.in/mgo.v2/bson/LICENSE new file mode 100644 index 000000000..890326017 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/LICENSE @@ -0,0 +1,25 @@ +BSON library for Go + +Copyright (c) 2010-2012 - Gustavo Niemeyer + +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. + +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/gopkg.in/mgo.v2/bson/bson.go b/vendor/gopkg.in/mgo.v2/bson/bson.go new file mode 100644 index 000000000..7fb7f8cae --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/bson.go @@ -0,0 +1,738 @@ +// BSON library for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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 bson is an implementation of the BSON specification for Go: +// +// http://bsonspec.org +// +// It was created as part of the mgo MongoDB driver for Go, but is standalone +// and may be used on its own without the driver. +package bson + +import ( + "bytes" + "crypto/md5" + "crypto/rand" + "encoding/binary" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "reflect" + "runtime" + "strings" + "sync" + "sync/atomic" + "time" +) + +// -------------------------------------------------------------------------- +// The public API. + +// A value implementing the bson.Getter interface will have its GetBSON +// method called when the given value has to be marshalled, and the result +// of this method will be marshaled in place of the actual object. +// +// If GetBSON returns return a non-nil error, the marshalling procedure +// will stop and error out with the provided value. +type Getter interface { + GetBSON() (interface{}, error) +} + +// A value implementing the bson.Setter interface will receive the BSON +// value via the SetBSON method during unmarshaling, and the object +// itself will not be changed as usual. +// +// If setting the value works, the method should return nil or alternatively +// bson.SetZero to set the respective field to its zero value (nil for +// pointer types). If SetBSON returns a value of type bson.TypeError, the +// BSON value will be omitted from a map or slice being decoded and the +// unmarshalling will continue. If it returns any other non-nil error, the +// unmarshalling procedure will stop and error out with the provided value. +// +// This interface is generally useful in pointer receivers, since the method +// will want to change the receiver. A type field that implements the Setter +// interface doesn't have to be a pointer, though. +// +// Unlike the usual behavior, unmarshalling onto a value that implements a +// Setter interface will NOT reset the value to its zero state. This allows +// the value to decide by itself how to be unmarshalled. +// +// For example: +// +// type MyString string +// +// func (s *MyString) SetBSON(raw bson.Raw) error { +// return raw.Unmarshal(s) +// } +// +type Setter interface { + SetBSON(raw Raw) error +} + +// SetZero may be returned from a SetBSON method to have the value set to +// its respective zero value. When used in pointer values, this will set the +// field to nil rather than to the pre-allocated value. +var SetZero = errors.New("set to zero") + +// M is a convenient alias for a map[string]interface{} map, useful for +// dealing with BSON in a native way. For instance: +// +// bson.M{"a": 1, "b": true} +// +// There's no special handling for this type in addition to what's done anyway +// for an equivalent map type. Elements in the map will be dumped in an +// undefined ordered. See also the bson.D type for an ordered alternative. +type M map[string]interface{} + +// D represents a BSON document containing ordered elements. For example: +// +// bson.D{{"a", 1}, {"b", true}} +// +// In some situations, such as when creating indexes for MongoDB, the order in +// which the elements are defined is important. If the order is not important, +// using a map is generally more comfortable. See bson.M and bson.RawD. +type D []DocElem + +// DocElem is an element of the bson.D document representation. +type DocElem struct { + Name string + Value interface{} +} + +// Map returns a map out of the ordered element name/value pairs in d. +func (d D) Map() (m M) { + m = make(M, len(d)) + for _, item := range d { + m[item.Name] = item.Value + } + return m +} + +// The Raw type represents raw unprocessed BSON documents and elements. +// Kind is the kind of element as defined per the BSON specification, and +// Data is the raw unprocessed data for the respective element. +// Using this type it is possible to unmarshal or marshal values partially. +// +// Relevant documentation: +// +// http://bsonspec.org/#/specification +// +type Raw struct { + Kind byte + Data []byte +} + +// RawD represents a BSON document containing raw unprocessed elements. +// This low-level representation may be useful when lazily processing +// documents of uncertain content, or when manipulating the raw content +// documents in general. +type RawD []RawDocElem + +// See the RawD type. +type RawDocElem struct { + Name string + Value Raw +} + +// ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes +// long. MongoDB objects by default have such a property set in their "_id" +// property. +// +// http://www.mongodb.org/display/DOCS/Object+IDs +type ObjectId string + +// ObjectIdHex returns an ObjectId from the provided hex representation. +// Calling this function with an invalid hex representation will +// cause a runtime panic. See the IsObjectIdHex function. +func ObjectIdHex(s string) ObjectId { + d, err := hex.DecodeString(s) + if err != nil || len(d) != 12 { + panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s)) + } + return ObjectId(d) +} + +// IsObjectIdHex returns whether s is a valid hex representation of +// an ObjectId. See the ObjectIdHex function. +func IsObjectIdHex(s string) bool { + if len(s) != 24 { + return false + } + _, err := hex.DecodeString(s) + return err == nil +} + +// objectIdCounter is atomically incremented when generating a new ObjectId +// using NewObjectId() function. It's used as a counter part of an id. +var objectIdCounter uint32 = readRandomUint32() + +// readRandomUint32 returns a random objectIdCounter. +func readRandomUint32() uint32 { + var b [4]byte + _, err := io.ReadFull(rand.Reader, b[:]) + if err != nil { + panic(fmt.Errorf("cannot read random object id: %v", err)) + } + return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)) +} + +// machineId stores machine id generated once and used in subsequent calls +// to NewObjectId function. +var machineId = readMachineId() +var processId = os.Getpid() + +// readMachineId generates and returns a machine id. +// If this function fails to get the hostname it will cause a runtime error. +func readMachineId() []byte { + var sum [3]byte + id := sum[:] + hostname, err1 := os.Hostname() + if err1 != nil { + _, err2 := io.ReadFull(rand.Reader, id) + if err2 != nil { + panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2)) + } + return id + } + hw := md5.New() + hw.Write([]byte(hostname)) + copy(id, hw.Sum(nil)) + return id +} + +// NewObjectId returns a new unique ObjectId. +func NewObjectId() ObjectId { + var b [12]byte + // Timestamp, 4 bytes, big endian + binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) + // Machine, first 3 bytes of md5(hostname) + b[4] = machineId[0] + b[5] = machineId[1] + b[6] = machineId[2] + // Pid, 2 bytes, specs don't specify endianness, but we use big endian. + b[7] = byte(processId >> 8) + b[8] = byte(processId) + // Increment, 3 bytes, big endian + i := atomic.AddUint32(&objectIdCounter, 1) + b[9] = byte(i >> 16) + b[10] = byte(i >> 8) + b[11] = byte(i) + return ObjectId(b[:]) +} + +// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled +// with the provided number of seconds from epoch UTC, and all other parts +// filled with zeroes. It's not safe to insert a document with an id generated +// by this method, it is useful only for queries to find documents with ids +// generated before or after the specified timestamp. +func NewObjectIdWithTime(t time.Time) ObjectId { + var b [12]byte + binary.BigEndian.PutUint32(b[:4], uint32(t.Unix())) + return ObjectId(string(b[:])) +} + +// String returns a hex string representation of the id. +// Example: ObjectIdHex("4d88e15b60f486e428412dc9"). +func (id ObjectId) String() string { + return fmt.Sprintf(`ObjectIdHex("%x")`, string(id)) +} + +// Hex returns a hex representation of the ObjectId. +func (id ObjectId) Hex() string { + return hex.EncodeToString([]byte(id)) +} + +// MarshalJSON turns a bson.ObjectId into a json.Marshaller. +func (id ObjectId) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%x"`, string(id))), nil +} + +var nullBytes = []byte("null") + +// UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller. +func (id *ObjectId) UnmarshalJSON(data []byte) error { + if len(data) > 0 && (data[0] == '{' || data[0] == 'O') { + var v struct { + Id json.RawMessage `json:"$oid"` + Func struct { + Id json.RawMessage + } `json:"$oidFunc"` + } + err := jdec(data, &v) + if err == nil { + if len(v.Id) > 0 { + data = []byte(v.Id) + } else { + data = []byte(v.Func.Id) + } + } + } + if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) { + *id = "" + return nil + } + if len(data) != 26 || data[0] != '"' || data[25] != '"' { + return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s", string(data))) + } + var buf [12]byte + _, err := hex.Decode(buf[:], data[1:25]) + if err != nil { + return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s (%s)", string(data), err)) + } + *id = ObjectId(string(buf[:])) + return nil +} + +// MarshalText turns bson.ObjectId into an encoding.TextMarshaler. +func (id ObjectId) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("%x", string(id))), nil +} + +// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler. +func (id *ObjectId) UnmarshalText(data []byte) error { + if len(data) == 1 && data[0] == ' ' || len(data) == 0 { + *id = "" + return nil + } + if len(data) != 24 { + return fmt.Errorf("invalid ObjectId: %s", data) + } + var buf [12]byte + _, err := hex.Decode(buf[:], data[:]) + if err != nil { + return fmt.Errorf("invalid ObjectId: %s (%s)", data, err) + } + *id = ObjectId(string(buf[:])) + return nil +} + +// Valid returns true if id is valid. A valid id must contain exactly 12 bytes. +func (id ObjectId) Valid() bool { + return len(id) == 12 +} + +// byteSlice returns byte slice of id from start to end. +// Calling this function with an invalid id will cause a runtime panic. +func (id ObjectId) byteSlice(start, end int) []byte { + if len(id) != 12 { + panic(fmt.Sprintf("invalid ObjectId: %q", string(id))) + } + return []byte(string(id)[start:end]) +} + +// Time returns the timestamp part of the id. +// It's a runtime error to call this method with an invalid id. +func (id ObjectId) Time() time.Time { + // First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. + secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4))) + return time.Unix(secs, 0) +} + +// Machine returns the 3-byte machine id part of the id. +// It's a runtime error to call this method with an invalid id. +func (id ObjectId) Machine() []byte { + return id.byteSlice(4, 7) +} + +// Pid returns the process id part of the id. +// It's a runtime error to call this method with an invalid id. +func (id ObjectId) Pid() uint16 { + return binary.BigEndian.Uint16(id.byteSlice(7, 9)) +} + +// Counter returns the incrementing value part of the id. +// It's a runtime error to call this method with an invalid id. +func (id ObjectId) Counter() int32 { + b := id.byteSlice(9, 12) + // Counter is stored as big-endian 3-byte value + return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) +} + +// The Symbol type is similar to a string and is used in languages with a +// distinct symbol type. +type Symbol string + +// Now returns the current time with millisecond precision. MongoDB stores +// timestamps with the same precision, so a Time returned from this method +// will not change after a roundtrip to the database. That's the only reason +// why this function exists. Using the time.Now function also works fine +// otherwise. +func Now() time.Time { + return time.Unix(0, time.Now().UnixNano()/1e6*1e6) +} + +// MongoTimestamp is a special internal type used by MongoDB that for some +// strange reason has its own datatype defined in BSON. +type MongoTimestamp int64 + +type orderKey int64 + +// MaxKey is a special value that compares higher than all other possible BSON +// values in a MongoDB database. +var MaxKey = orderKey(1<<63 - 1) + +// MinKey is a special value that compares lower than all other possible BSON +// values in a MongoDB database. +var MinKey = orderKey(-1 << 63) + +type undefined struct{} + +// Undefined represents the undefined BSON value. +var Undefined undefined + +// Binary is a representation for non-standard binary values. Any kind should +// work, but the following are known as of this writing: +// +// 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}. +// 0x01 - Function (!?) +// 0x02 - Obsolete generic. +// 0x03 - UUID +// 0x05 - MD5 +// 0x80 - User defined. +// +type Binary struct { + Kind byte + Data []byte +} + +// RegEx represents a regular expression. The Options field may contain +// individual characters defining the way in which the pattern should be +// applied, and must be sorted. Valid options as of this writing are 'i' for +// case insensitive matching, 'm' for multi-line matching, 'x' for verbose +// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all +// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match +// unicode. The value of the Options parameter is not verified before being +// marshaled into the BSON format. +type RegEx struct { + Pattern string + Options string +} + +// JavaScript is a type that holds JavaScript code. If Scope is non-nil, it +// will be marshaled as a mapping from identifiers to values that may be +// used when evaluating the provided Code. +type JavaScript struct { + Code string + Scope interface{} +} + +// DBPointer refers to a document id in a namespace. +// +// This type is deprecated in the BSON specification and should not be used +// except for backwards compatibility with ancient applications. +type DBPointer struct { + Namespace string + Id ObjectId +} + +const initialBufferSize = 64 + +func handleErr(err *error) { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } else if _, ok := r.(externalPanic); ok { + panic(r) + } else if s, ok := r.(string); ok { + *err = errors.New(s) + } else if e, ok := r.(error); ok { + *err = e + } else { + panic(r) + } + } +} + +// Marshal serializes the in value, which may be a map or a struct value. +// In the case of struct values, only exported fields will be serialized, +// and the order of serialized fields will match that of the struct itself. +// The lowercased field name is used as the key for each exported field, +// but this behavior may be changed using the respective field tag. +// The tag may also contain flags to tweak the marshalling behavior for +// the field. The tag formats accepted are: +// +// "[][,[,]]" +// +// `(...) bson:"[][,[,]]" (...)` +// +// The following flags are currently supported: +// +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// +// minsize Marshal an int64 value as an int32, if that's feasible +// while preserving the numeric value. +// +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the bson keys of other struct fields. +// +// Some examples: +// +// type T struct { +// A bool +// B int "myb" +// C string "myc,omitempty" +// D string `bson:",omitempty" json:"jsonkey"` +// E int64 ",minsize" +// F int64 "myf,omitempty,minsize" +// } +// +func Marshal(in interface{}) (out []byte, err error) { + defer handleErr(&err) + e := &encoder{make([]byte, 0, initialBufferSize)} + e.addDoc(reflect.ValueOf(in)) + return e.out, nil +} + +// Unmarshal deserializes data from in into the out value. The out value +// must be a map, a pointer to a struct, or a pointer to a bson.D value. +// In the case of struct values, only exported fields will be deserialized. +// The lowercased field name is used as the key for each exported field, +// but this behavior may be changed using the respective field tag. +// The tag may also contain flags to tweak the marshalling behavior for +// the field. The tag formats accepted are: +// +// "[][,[,]]" +// +// `(...) bson:"[][,[,]]" (...)` +// +// The following flags are currently supported during unmarshal (see the +// Marshal method for other flags): +// +// inline Inline the field, which must be a struct or a map. +// Inlined structs are handled as if its fields were part +// of the outer struct. An inlined map causes keys that do +// not match any other struct field to be inserted in the +// map rather than being discarded as usual. +// +// The target field or element types of out may not necessarily match +// the BSON values of the provided data. The following conversions are +// made automatically: +// +// - Numeric types are converted if at least the integer part of the +// value would be preserved correctly +// - Bools are converted to numeric types as 1 or 0 +// - Numeric types are converted to bools as true if not 0 or false otherwise +// - Binary and string BSON data is converted to a string, array or byte slice +// +// If the value would not fit the type and cannot be converted, it's +// silently skipped. +// +// Pointer values are initialized when necessary. +func Unmarshal(in []byte, out interface{}) (err error) { + if raw, ok := out.(*Raw); ok { + raw.Kind = 3 + raw.Data = in + return nil + } + defer handleErr(&err) + v := reflect.ValueOf(out) + switch v.Kind() { + case reflect.Ptr: + fallthrough + case reflect.Map: + d := newDecoder(in) + d.readDocTo(v) + case reflect.Struct: + return errors.New("Unmarshal can't deal with struct values. Use a pointer.") + default: + return errors.New("Unmarshal needs a map or a pointer to a struct.") + } + return nil +} + +// Unmarshal deserializes raw into the out value. If the out value type +// is not compatible with raw, a *bson.TypeError is returned. +// +// See the Unmarshal function documentation for more details on the +// unmarshalling process. +func (raw Raw) Unmarshal(out interface{}) (err error) { + defer handleErr(&err) + v := reflect.ValueOf(out) + switch v.Kind() { + case reflect.Ptr: + v = v.Elem() + fallthrough + case reflect.Map: + d := newDecoder(raw.Data) + good := d.readElemTo(v, raw.Kind) + if !good { + return &TypeError{v.Type(), raw.Kind} + } + case reflect.Struct: + return errors.New("Raw Unmarshal can't deal with struct values. Use a pointer.") + default: + return errors.New("Raw Unmarshal needs a map or a valid pointer.") + } + return nil +} + +type TypeError struct { + Type reflect.Type + Kind byte +} + +func (e *TypeError) Error() string { + return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String()) +} + +// -------------------------------------------------------------------------- +// Maintain a mapping of keys to structure field indexes + +type structInfo struct { + FieldsMap map[string]fieldInfo + FieldsList []fieldInfo + InlineMap int + Zero reflect.Value +} + +type fieldInfo struct { + Key string + Num int + OmitEmpty bool + MinSize bool + Inline []int +} + +var structMap = make(map[reflect.Type]*structInfo) +var structMapMutex sync.RWMutex + +type externalPanic string + +func (e externalPanic) String() string { + return string(e) +} + +func getStructInfo(st reflect.Type) (*structInfo, error) { + structMapMutex.RLock() + sinfo, found := structMap[st] + structMapMutex.RUnlock() + if found { + return sinfo, nil + } + n := st.NumField() + fieldsMap := make(map[string]fieldInfo) + fieldsList := make([]fieldInfo, 0, n) + inlineMap := -1 + for i := 0; i != n; i++ { + field := st.Field(i) + if field.PkgPath != "" && !field.Anonymous { + continue // Private field + } + + info := fieldInfo{Num: i} + + tag := field.Tag.Get("bson") + if tag == "" && strings.Index(string(field.Tag), ":") < 0 { + tag = string(field.Tag) + } + if tag == "-" { + continue + } + + inline := false + fields := strings.Split(tag, ",") + if len(fields) > 1 { + for _, flag := range fields[1:] { + switch flag { + case "omitempty": + info.OmitEmpty = true + case "minsize": + info.MinSize = true + case "inline": + inline = true + default: + msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st) + panic(externalPanic(msg)) + } + } + tag = fields[0] + } + + if inline { + switch field.Type.Kind() { + case reflect.Map: + if inlineMap >= 0 { + return nil, errors.New("Multiple ,inline maps in struct " + st.String()) + } + if field.Type.Key() != reflect.TypeOf("") { + return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) + } + inlineMap = info.Num + case reflect.Struct: + sinfo, err := getStructInfo(field.Type) + if err != nil { + return nil, err + } + for _, finfo := range sinfo.FieldsList { + if _, found := fieldsMap[finfo.Key]; found { + msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + if finfo.Inline == nil { + finfo.Inline = []int{i, finfo.Num} + } else { + finfo.Inline = append([]int{i}, finfo.Inline...) + } + fieldsMap[finfo.Key] = finfo + fieldsList = append(fieldsList, finfo) + } + default: + panic("Option ,inline needs a struct value or map field") + } + continue + } + + if tag != "" { + info.Key = tag + } else { + info.Key = strings.ToLower(field.Name) + } + + if _, found = fieldsMap[info.Key]; found { + msg := "Duplicated key '" + info.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + + fieldsList = append(fieldsList, info) + fieldsMap[info.Key] = info + } + sinfo = &structInfo{ + fieldsMap, + fieldsList, + inlineMap, + reflect.New(st).Elem(), + } + structMapMutex.Lock() + structMap[st] = sinfo + structMapMutex.Unlock() + return sinfo, nil +} diff --git a/vendor/gopkg.in/mgo.v2/bson/decimal.go b/vendor/gopkg.in/mgo.v2/bson/decimal.go new file mode 100644 index 000000000..3d2f70020 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/decimal.go @@ -0,0 +1,310 @@ +// BSON library for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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 bson + +import ( + "fmt" + "strconv" + "strings" +) + +// Decimal128 holds decimal128 BSON values. +type Decimal128 struct { + h, l uint64 +} + +func (d Decimal128) String() string { + var pos int // positive sign + var e int // exponent + var h, l uint64 // significand high/low + + if d.h>>63&1 == 0 { + pos = 1 + } + + switch d.h >> 58 & (1<<5 - 1) { + case 0x1F: + return "NaN" + case 0x1E: + return "-Inf"[pos:] + } + + l = d.l + if d.h>>61&3 == 3 { + // Bits: 1*sign 2*ignored 14*exponent 111*significand. + // Implicit 0b100 prefix in significand. + e = int(d.h>>47&(1<<14-1)) - 6176 + //h = 4<<47 | d.h&(1<<47-1) + // Spec says all of these values are out of range. + h, l = 0, 0 + } else { + // Bits: 1*sign 14*exponent 113*significand + e = int(d.h>>49&(1<<14-1)) - 6176 + h = d.h & (1<<49 - 1) + } + + // Would be handled by the logic below, but that's trivial and common. + if h == 0 && l == 0 && e == 0 { + return "-0"[pos:] + } + + var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero. + var last = len(repr) + var i = len(repr) + var dot = len(repr) + e + var rem uint32 +Loop: + for d9 := 0; d9 < 5; d9++ { + h, l, rem = divmod(h, l, 1e9) + for d1 := 0; d1 < 9; d1++ { + // Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc. + if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) { + e += len(repr) - i + i-- + repr[i] = '.' + last = i - 1 + dot = len(repr) // Unmark. + } + c := '0' + byte(rem%10) + rem /= 10 + i-- + repr[i] = c + // Handle "0E+3", "1E+3", etc. + if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) { + last = i + break Loop + } + if c != '0' { + last = i + } + // Break early. Works without it, but why. + if dot > i && l == 0 && h == 0 && rem == 0 { + break Loop + } + } + } + repr[last-1] = '-' + last-- + + if e > 0 { + return string(repr[last+pos:]) + "E+" + strconv.Itoa(e) + } + if e < 0 { + return string(repr[last+pos:]) + "E" + strconv.Itoa(e) + } + return string(repr[last+pos:]) +} + +func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) { + div64 := uint64(div) + a := h >> 32 + aq := a / div64 + ar := a % div64 + b := ar<<32 + h&(1<<32-1) + bq := b / div64 + br := b % div64 + c := br<<32 + l>>32 + cq := c / div64 + cr := c % div64 + d := cr<<32 + l&(1<<32-1) + dq := d / div64 + dr := d % div64 + return (aq<<32 | bq), (cq<<32 | dq), uint32(dr) +} + +var dNaN = Decimal128{0x1F << 58, 0} +var dPosInf = Decimal128{0x1E << 58, 0} +var dNegInf = Decimal128{0x3E << 58, 0} + +func dErr(s string) (Decimal128, error) { + return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s) +} + +func ParseDecimal128(s string) (Decimal128, error) { + orig := s + if s == "" { + return dErr(orig) + } + neg := s[0] == '-' + if neg || s[0] == '+' { + s = s[1:] + } + + if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') { + if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") { + return dNaN, nil + } + if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { + if neg { + return dNegInf, nil + } + return dPosInf, nil + } + return dErr(orig) + } + + var h, l uint64 + var e int + + var add, ovr uint32 + var mul uint32 = 1 + var dot = -1 + var digits = 0 + var i = 0 + for i < len(s) { + c := s[i] + if mul == 1e9 { + h, l, ovr = muladd(h, l, mul, add) + mul, add = 1, 0 + if ovr > 0 || h&((1<<15-1)<<49) > 0 { + return dErr(orig) + } + } + if c >= '0' && c <= '9' { + i++ + if c > '0' || digits > 0 { + digits++ + } + if digits > 34 { + if c == '0' { + // Exact rounding. + e++ + continue + } + return dErr(orig) + } + mul *= 10 + add *= 10 + add += uint32(c - '0') + continue + } + if c == '.' { + i++ + if dot >= 0 || i == 1 && len(s) == 1 { + return dErr(orig) + } + if i == len(s) { + break + } + if s[i] < '0' || s[i] > '9' || e > 0 { + return dErr(orig) + } + dot = i + continue + } + break + } + if i == 0 { + return dErr(orig) + } + if mul > 1 { + h, l, ovr = muladd(h, l, mul, add) + if ovr > 0 || h&((1<<15-1)<<49) > 0 { + return dErr(orig) + } + } + if dot >= 0 { + e += dot - i + } + if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') { + i++ + eneg := s[i] == '-' + if eneg || s[i] == '+' { + i++ + if i == len(s) { + return dErr(orig) + } + } + n := 0 + for i < len(s) && n < 1e4 { + c := s[i] + i++ + if c < '0' || c > '9' { + return dErr(orig) + } + n *= 10 + n += int(c - '0') + } + if eneg { + n = -n + } + e += n + for e < -6176 { + // Subnormal. + var div uint32 = 1 + for div < 1e9 && e < -6176 { + div *= 10 + e++ + } + var rem uint32 + h, l, rem = divmod(h, l, div) + if rem > 0 { + return dErr(orig) + } + } + for e > 6111 { + // Clamped. + var mul uint32 = 1 + for mul < 1e9 && e > 6111 { + mul *= 10 + e-- + } + h, l, ovr = muladd(h, l, mul, 0) + if ovr > 0 || h&((1<<15-1)<<49) > 0 { + return dErr(orig) + } + } + if e < -6176 || e > 6111 { + return dErr(orig) + } + } + + if i < len(s) { + return dErr(orig) + } + + h |= uint64(e+6176) & uint64(1<<14-1) << 49 + if neg { + h |= 1 << 63 + } + return Decimal128{h, l}, nil +} + +func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) { + mul64 := uint64(mul) + a := mul64 * (l & (1<<32 - 1)) + b := a>>32 + mul64*(l>>32) + c := b>>32 + mul64*(h&(1<<32-1)) + d := c>>32 + mul64*(h>>32) + + a = a&(1<<32-1) + uint64(add) + b = b&(1<<32-1) + a>>32 + c = c&(1<<32-1) + b>>32 + d = d&(1<<32-1) + c>>32 + + return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32) +} diff --git a/vendor/gopkg.in/mgo.v2/bson/decode.go b/vendor/gopkg.in/mgo.v2/bson/decode.go new file mode 100644 index 000000000..7c2d8416a --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/decode.go @@ -0,0 +1,849 @@ +// BSON library for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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. +// gobson - BSON library for Go. + +package bson + +import ( + "fmt" + "math" + "net/url" + "reflect" + "strconv" + "sync" + "time" +) + +type decoder struct { + in []byte + i int + docType reflect.Type +} + +var typeM = reflect.TypeOf(M{}) + +func newDecoder(in []byte) *decoder { + return &decoder{in, 0, typeM} +} + +// -------------------------------------------------------------------------- +// Some helper functions. + +func corrupted() { + panic("Document is corrupted") +} + +func settableValueOf(i interface{}) reflect.Value { + v := reflect.ValueOf(i) + sv := reflect.New(v.Type()).Elem() + sv.Set(v) + return sv +} + +// -------------------------------------------------------------------------- +// Unmarshaling of documents. + +const ( + setterUnknown = iota + setterNone + setterType + setterAddr +) + +var setterStyles map[reflect.Type]int +var setterIface reflect.Type +var setterMutex sync.RWMutex + +func init() { + var iface Setter + setterIface = reflect.TypeOf(&iface).Elem() + setterStyles = make(map[reflect.Type]int) +} + +func setterStyle(outt reflect.Type) int { + setterMutex.RLock() + style := setterStyles[outt] + setterMutex.RUnlock() + if style == setterUnknown { + setterMutex.Lock() + defer setterMutex.Unlock() + if outt.Implements(setterIface) { + setterStyles[outt] = setterType + } else if reflect.PtrTo(outt).Implements(setterIface) { + setterStyles[outt] = setterAddr + } else { + setterStyles[outt] = setterNone + } + style = setterStyles[outt] + } + return style +} + +func getSetter(outt reflect.Type, out reflect.Value) Setter { + style := setterStyle(outt) + if style == setterNone { + return nil + } + if style == setterAddr { + if !out.CanAddr() { + return nil + } + out = out.Addr() + } else if outt.Kind() == reflect.Ptr && out.IsNil() { + out.Set(reflect.New(outt.Elem())) + } + return out.Interface().(Setter) +} + +func clearMap(m reflect.Value) { + var none reflect.Value + for _, k := range m.MapKeys() { + m.SetMapIndex(k, none) + } +} + +func (d *decoder) readDocTo(out reflect.Value) { + var elemType reflect.Type + outt := out.Type() + outk := outt.Kind() + + for { + if outk == reflect.Ptr && out.IsNil() { + out.Set(reflect.New(outt.Elem())) + } + if setter := getSetter(outt, out); setter != nil { + var raw Raw + d.readDocTo(reflect.ValueOf(&raw)) + err := setter.SetBSON(raw) + if _, ok := err.(*TypeError); err != nil && !ok { + panic(err) + } + return + } + if outk == reflect.Ptr { + out = out.Elem() + outt = out.Type() + outk = out.Kind() + continue + } + break + } + + var fieldsMap map[string]fieldInfo + var inlineMap reflect.Value + start := d.i + + origout := out + if outk == reflect.Interface { + if d.docType.Kind() == reflect.Map { + mv := reflect.MakeMap(d.docType) + out.Set(mv) + out = mv + } else { + dv := reflect.New(d.docType).Elem() + out.Set(dv) + out = dv + } + outt = out.Type() + outk = outt.Kind() + } + + docType := d.docType + keyType := typeString + convertKey := false + switch outk { + case reflect.Map: + keyType = outt.Key() + if keyType.Kind() != reflect.String { + panic("BSON map must have string keys. Got: " + outt.String()) + } + if keyType != typeString { + convertKey = true + } + elemType = outt.Elem() + if elemType == typeIface { + d.docType = outt + } + if out.IsNil() { + out.Set(reflect.MakeMap(out.Type())) + } else if out.Len() > 0 { + clearMap(out) + } + case reflect.Struct: + if outt != typeRaw { + sinfo, err := getStructInfo(out.Type()) + if err != nil { + panic(err) + } + fieldsMap = sinfo.FieldsMap + out.Set(sinfo.Zero) + if sinfo.InlineMap != -1 { + inlineMap = out.Field(sinfo.InlineMap) + if !inlineMap.IsNil() && inlineMap.Len() > 0 { + clearMap(inlineMap) + } + elemType = inlineMap.Type().Elem() + if elemType == typeIface { + d.docType = inlineMap.Type() + } + } + } + case reflect.Slice: + switch outt.Elem() { + case typeDocElem: + origout.Set(d.readDocElems(outt)) + return + case typeRawDocElem: + origout.Set(d.readRawDocElems(outt)) + return + } + fallthrough + default: + panic("Unsupported document type for unmarshalling: " + out.Type().String()) + } + + end := int(d.readInt32()) + end += d.i - 4 + if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { + corrupted() + } + for d.in[d.i] != '\x00' { + kind := d.readByte() + name := d.readCStr() + if d.i >= end { + corrupted() + } + + switch outk { + case reflect.Map: + e := reflect.New(elemType).Elem() + if d.readElemTo(e, kind) { + k := reflect.ValueOf(name) + if convertKey { + k = k.Convert(keyType) + } + out.SetMapIndex(k, e) + } + case reflect.Struct: + if outt == typeRaw { + d.dropElem(kind) + } else { + if info, ok := fieldsMap[name]; ok { + if info.Inline == nil { + d.readElemTo(out.Field(info.Num), kind) + } else { + d.readElemTo(out.FieldByIndex(info.Inline), kind) + } + } else if inlineMap.IsValid() { + if inlineMap.IsNil() { + inlineMap.Set(reflect.MakeMap(inlineMap.Type())) + } + e := reflect.New(elemType).Elem() + if d.readElemTo(e, kind) { + inlineMap.SetMapIndex(reflect.ValueOf(name), e) + } + } else { + d.dropElem(kind) + } + } + case reflect.Slice: + } + + if d.i >= end { + corrupted() + } + } + d.i++ // '\x00' + if d.i != end { + corrupted() + } + d.docType = docType + + if outt == typeRaw { + out.Set(reflect.ValueOf(Raw{0x03, d.in[start:d.i]})) + } +} + +func (d *decoder) readArrayDocTo(out reflect.Value) { + end := int(d.readInt32()) + end += d.i - 4 + if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { + corrupted() + } + i := 0 + l := out.Len() + for d.in[d.i] != '\x00' { + if i >= l { + panic("Length mismatch on array field") + } + kind := d.readByte() + for d.i < end && d.in[d.i] != '\x00' { + d.i++ + } + if d.i >= end { + corrupted() + } + d.i++ + d.readElemTo(out.Index(i), kind) + if d.i >= end { + corrupted() + } + i++ + } + if i != l { + panic("Length mismatch on array field") + } + d.i++ // '\x00' + if d.i != end { + corrupted() + } +} + +func (d *decoder) readSliceDoc(t reflect.Type) interface{} { + tmp := make([]reflect.Value, 0, 8) + elemType := t.Elem() + if elemType == typeRawDocElem { + d.dropElem(0x04) + return reflect.Zero(t).Interface() + } + + end := int(d.readInt32()) + end += d.i - 4 + if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { + corrupted() + } + for d.in[d.i] != '\x00' { + kind := d.readByte() + for d.i < end && d.in[d.i] != '\x00' { + d.i++ + } + if d.i >= end { + corrupted() + } + d.i++ + e := reflect.New(elemType).Elem() + if d.readElemTo(e, kind) { + tmp = append(tmp, e) + } + if d.i >= end { + corrupted() + } + } + d.i++ // '\x00' + if d.i != end { + corrupted() + } + + n := len(tmp) + slice := reflect.MakeSlice(t, n, n) + for i := 0; i != n; i++ { + slice.Index(i).Set(tmp[i]) + } + return slice.Interface() +} + +var typeSlice = reflect.TypeOf([]interface{}{}) +var typeIface = typeSlice.Elem() + +func (d *decoder) readDocElems(typ reflect.Type) reflect.Value { + docType := d.docType + d.docType = typ + slice := make([]DocElem, 0, 8) + d.readDocWith(func(kind byte, name string) { + e := DocElem{Name: name} + v := reflect.ValueOf(&e.Value) + if d.readElemTo(v.Elem(), kind) { + slice = append(slice, e) + } + }) + slicev := reflect.New(typ).Elem() + slicev.Set(reflect.ValueOf(slice)) + d.docType = docType + return slicev +} + +func (d *decoder) readRawDocElems(typ reflect.Type) reflect.Value { + docType := d.docType + d.docType = typ + slice := make([]RawDocElem, 0, 8) + d.readDocWith(func(kind byte, name string) { + e := RawDocElem{Name: name} + v := reflect.ValueOf(&e.Value) + if d.readElemTo(v.Elem(), kind) { + slice = append(slice, e) + } + }) + slicev := reflect.New(typ).Elem() + slicev.Set(reflect.ValueOf(slice)) + d.docType = docType + return slicev +} + +func (d *decoder) readDocWith(f func(kind byte, name string)) { + end := int(d.readInt32()) + end += d.i - 4 + if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { + corrupted() + } + for d.in[d.i] != '\x00' { + kind := d.readByte() + name := d.readCStr() + if d.i >= end { + corrupted() + } + f(kind, name) + if d.i >= end { + corrupted() + } + } + d.i++ // '\x00' + if d.i != end { + corrupted() + } +} + +// -------------------------------------------------------------------------- +// Unmarshaling of individual elements within a document. + +var blackHole = settableValueOf(struct{}{}) + +func (d *decoder) dropElem(kind byte) { + d.readElemTo(blackHole, kind) +} + +// Attempt to decode an element from the document and put it into out. +// If the types are not compatible, the returned ok value will be +// false and out will be unchanged. +func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) { + + start := d.i + + if kind == 0x03 { + // Delegate unmarshaling of documents. + outt := out.Type() + outk := out.Kind() + switch outk { + case reflect.Interface, reflect.Ptr, reflect.Struct, reflect.Map: + d.readDocTo(out) + return true + } + if setterStyle(outt) != setterNone { + d.readDocTo(out) + return true + } + if outk == reflect.Slice { + switch outt.Elem() { + case typeDocElem: + out.Set(d.readDocElems(outt)) + case typeRawDocElem: + out.Set(d.readRawDocElems(outt)) + default: + d.readDocTo(blackHole) + } + return true + } + d.readDocTo(blackHole) + return true + } + + var in interface{} + + switch kind { + case 0x01: // Float64 + in = d.readFloat64() + case 0x02: // UTF-8 string + in = d.readStr() + case 0x03: // Document + panic("Can't happen. Handled above.") + case 0x04: // Array + outt := out.Type() + if setterStyle(outt) != setterNone { + // Skip the value so its data is handed to the setter below. + d.dropElem(kind) + break + } + for outt.Kind() == reflect.Ptr { + outt = outt.Elem() + } + switch outt.Kind() { + case reflect.Array: + d.readArrayDocTo(out) + return true + case reflect.Slice: + in = d.readSliceDoc(outt) + default: + in = d.readSliceDoc(typeSlice) + } + case 0x05: // Binary + b := d.readBinary() + if b.Kind == 0x00 || b.Kind == 0x02 { + in = b.Data + } else { + in = b + } + case 0x06: // Undefined (obsolete, but still seen in the wild) + in = Undefined + case 0x07: // ObjectId + in = ObjectId(d.readBytes(12)) + case 0x08: // Bool + in = d.readBool() + case 0x09: // Timestamp + // MongoDB handles timestamps as milliseconds. + i := d.readInt64() + if i == -62135596800000 { + in = time.Time{} // In UTC for convenience. + } else { + in = time.Unix(i/1e3, i%1e3*1e6) + } + case 0x0A: // Nil + in = nil + case 0x0B: // RegEx + in = d.readRegEx() + case 0x0C: + in = DBPointer{Namespace: d.readStr(), Id: ObjectId(d.readBytes(12))} + case 0x0D: // JavaScript without scope + in = JavaScript{Code: d.readStr()} + case 0x0E: // Symbol + in = Symbol(d.readStr()) + case 0x0F: // JavaScript with scope + d.i += 4 // Skip length + js := JavaScript{d.readStr(), make(M)} + d.readDocTo(reflect.ValueOf(js.Scope)) + in = js + case 0x10: // Int32 + in = int(d.readInt32()) + case 0x11: // Mongo-specific timestamp + in = MongoTimestamp(d.readInt64()) + case 0x12: // Int64 + in = d.readInt64() + case 0x13: // Decimal128 + in = Decimal128{ + l: uint64(d.readInt64()), + h: uint64(d.readInt64()), + } + case 0x7F: // Max key + in = MaxKey + case 0xFF: // Min key + in = MinKey + default: + panic(fmt.Sprintf("Unknown element kind (0x%02X)", kind)) + } + + outt := out.Type() + + if outt == typeRaw { + out.Set(reflect.ValueOf(Raw{kind, d.in[start:d.i]})) + return true + } + + if setter := getSetter(outt, out); setter != nil { + err := setter.SetBSON(Raw{kind, d.in[start:d.i]}) + if err == SetZero { + out.Set(reflect.Zero(outt)) + return true + } + if err == nil { + return true + } + if _, ok := err.(*TypeError); !ok { + panic(err) + } + return false + } + + if in == nil { + out.Set(reflect.Zero(outt)) + return true + } + + outk := outt.Kind() + + // Dereference and initialize pointer if necessary. + first := true + for outk == reflect.Ptr { + if !out.IsNil() { + out = out.Elem() + } else { + elem := reflect.New(outt.Elem()) + if first { + // Only set if value is compatible. + first = false + defer func(out, elem reflect.Value) { + if good { + out.Set(elem) + } + }(out, elem) + } else { + out.Set(elem) + } + out = elem + } + outt = out.Type() + outk = outt.Kind() + } + + inv := reflect.ValueOf(in) + if outt == inv.Type() { + out.Set(inv) + return true + } + + switch outk { + case reflect.Interface: + out.Set(inv) + return true + case reflect.String: + switch inv.Kind() { + case reflect.String: + out.SetString(inv.String()) + return true + case reflect.Slice: + if b, ok := in.([]byte); ok { + out.SetString(string(b)) + return true + } + case reflect.Int, reflect.Int64: + if outt == typeJSONNumber { + out.SetString(strconv.FormatInt(inv.Int(), 10)) + return true + } + case reflect.Float64: + if outt == typeJSONNumber { + out.SetString(strconv.FormatFloat(inv.Float(), 'f', -1, 64)) + return true + } + } + case reflect.Slice, reflect.Array: + // Remember, array (0x04) slices are built with the correct + // element type. If we are here, must be a cross BSON kind + // conversion (e.g. 0x05 unmarshalling on string). + if outt.Elem().Kind() != reflect.Uint8 { + break + } + switch inv.Kind() { + case reflect.String: + slice := []byte(inv.String()) + out.Set(reflect.ValueOf(slice)) + return true + case reflect.Slice: + switch outt.Kind() { + case reflect.Array: + reflect.Copy(out, inv) + case reflect.Slice: + out.SetBytes(inv.Bytes()) + } + return true + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch inv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + out.SetInt(inv.Int()) + return true + case reflect.Float32, reflect.Float64: + out.SetInt(int64(inv.Float())) + return true + case reflect.Bool: + if inv.Bool() { + out.SetInt(1) + } else { + out.SetInt(0) + } + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + panic("can't happen: no uint types in BSON (!?)") + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + switch inv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + out.SetUint(uint64(inv.Int())) + return true + case reflect.Float32, reflect.Float64: + out.SetUint(uint64(inv.Float())) + return true + case reflect.Bool: + if inv.Bool() { + out.SetUint(1) + } else { + out.SetUint(0) + } + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + panic("Can't happen. No uint types in BSON.") + } + case reflect.Float32, reflect.Float64: + switch inv.Kind() { + case reflect.Float32, reflect.Float64: + out.SetFloat(inv.Float()) + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + out.SetFloat(float64(inv.Int())) + return true + case reflect.Bool: + if inv.Bool() { + out.SetFloat(1) + } else { + out.SetFloat(0) + } + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + panic("Can't happen. No uint types in BSON?") + } + case reflect.Bool: + switch inv.Kind() { + case reflect.Bool: + out.SetBool(inv.Bool()) + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + out.SetBool(inv.Int() != 0) + return true + case reflect.Float32, reflect.Float64: + out.SetBool(inv.Float() != 0) + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + panic("Can't happen. No uint types in BSON?") + } + case reflect.Struct: + if outt == typeURL && inv.Kind() == reflect.String { + u, err := url.Parse(inv.String()) + if err != nil { + panic(err) + } + out.Set(reflect.ValueOf(u).Elem()) + return true + } + if outt == typeBinary { + if b, ok := in.([]byte); ok { + out.Set(reflect.ValueOf(Binary{Data: b})) + return true + } + } + } + + return false +} + +// -------------------------------------------------------------------------- +// Parsers of basic types. + +func (d *decoder) readRegEx() RegEx { + re := RegEx{} + re.Pattern = d.readCStr() + re.Options = d.readCStr() + return re +} + +func (d *decoder) readBinary() Binary { + l := d.readInt32() + b := Binary{} + b.Kind = d.readByte() + b.Data = d.readBytes(l) + if b.Kind == 0x02 && len(b.Data) >= 4 { + // Weird obsolete format with redundant length. + b.Data = b.Data[4:] + } + return b +} + +func (d *decoder) readStr() string { + l := d.readInt32() + b := d.readBytes(l - 1) + if d.readByte() != '\x00' { + corrupted() + } + return string(b) +} + +func (d *decoder) readCStr() string { + start := d.i + end := start + l := len(d.in) + for ; end != l; end++ { + if d.in[end] == '\x00' { + break + } + } + d.i = end + 1 + if d.i > l { + corrupted() + } + return string(d.in[start:end]) +} + +func (d *decoder) readBool() bool { + b := d.readByte() + if b == 0 { + return false + } + if b == 1 { + return true + } + panic(fmt.Sprintf("encoded boolean must be 1 or 0, found %d", b)) +} + +func (d *decoder) readFloat64() float64 { + return math.Float64frombits(uint64(d.readInt64())) +} + +func (d *decoder) readInt32() int32 { + b := d.readBytes(4) + return int32((uint32(b[0]) << 0) | + (uint32(b[1]) << 8) | + (uint32(b[2]) << 16) | + (uint32(b[3]) << 24)) +} + +func (d *decoder) readInt64() int64 { + b := d.readBytes(8) + return int64((uint64(b[0]) << 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)) +} + +func (d *decoder) readByte() byte { + i := d.i + d.i++ + if d.i > len(d.in) { + corrupted() + } + return d.in[i] +} + +func (d *decoder) readBytes(length int32) []byte { + if length < 0 { + corrupted() + } + start := d.i + d.i += int(length) + if d.i < start || d.i > len(d.in) { + corrupted() + } + return d.in[start : start+int(length)] +} diff --git a/vendor/gopkg.in/mgo.v2/bson/encode.go b/vendor/gopkg.in/mgo.v2/bson/encode.go new file mode 100644 index 000000000..add39e865 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/encode.go @@ -0,0 +1,514 @@ +// BSON library for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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. +// gobson - BSON library for Go. + +package bson + +import ( + "encoding/json" + "fmt" + "math" + "net/url" + "reflect" + "strconv" + "time" +) + +// -------------------------------------------------------------------------- +// Some internal infrastructure. + +var ( + typeBinary = reflect.TypeOf(Binary{}) + typeObjectId = reflect.TypeOf(ObjectId("")) + typeDBPointer = reflect.TypeOf(DBPointer{"", ObjectId("")}) + typeSymbol = reflect.TypeOf(Symbol("")) + typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0)) + typeOrderKey = reflect.TypeOf(MinKey) + typeDocElem = reflect.TypeOf(DocElem{}) + typeRawDocElem = reflect.TypeOf(RawDocElem{}) + typeRaw = reflect.TypeOf(Raw{}) + typeURL = reflect.TypeOf(url.URL{}) + typeTime = reflect.TypeOf(time.Time{}) + typeString = reflect.TypeOf("") + typeJSONNumber = reflect.TypeOf(json.Number("")) +) + +const itoaCacheSize = 32 + +var itoaCache []string + +func init() { + itoaCache = make([]string, itoaCacheSize) + for i := 0; i != itoaCacheSize; i++ { + itoaCache[i] = strconv.Itoa(i) + } +} + +func itoa(i int) string { + if i < itoaCacheSize { + return itoaCache[i] + } + return strconv.Itoa(i) +} + +// -------------------------------------------------------------------------- +// Marshaling of the document value itself. + +type encoder struct { + out []byte +} + +func (e *encoder) addDoc(v reflect.Value) { + for { + if vi, ok := v.Interface().(Getter); ok { + getv, err := vi.GetBSON() + if err != nil { + panic(err) + } + v = reflect.ValueOf(getv) + continue + } + if v.Kind() == reflect.Ptr { + v = v.Elem() + continue + } + break + } + + if v.Type() == typeRaw { + raw := v.Interface().(Raw) + if raw.Kind != 0x03 && raw.Kind != 0x00 { + panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document") + } + if len(raw.Data) == 0 { + panic("Attempted to marshal empty Raw document") + } + e.addBytes(raw.Data...) + return + } + + start := e.reserveInt32() + + switch v.Kind() { + case reflect.Map: + e.addMap(v) + case reflect.Struct: + e.addStruct(v) + case reflect.Array, reflect.Slice: + e.addSlice(v) + default: + panic("Can't marshal " + v.Type().String() + " as a BSON document") + } + + e.addBytes(0) + e.setInt32(start, int32(len(e.out)-start)) +} + +func (e *encoder) addMap(v reflect.Value) { + for _, k := range v.MapKeys() { + e.addElem(k.String(), v.MapIndex(k), false) + } +} + +func (e *encoder) addStruct(v reflect.Value) { + sinfo, err := getStructInfo(v.Type()) + if err != nil { + panic(err) + } + var value reflect.Value + if sinfo.InlineMap >= 0 { + m := v.Field(sinfo.InlineMap) + if m.Len() > 0 { + for _, k := range m.MapKeys() { + ks := k.String() + if _, found := sinfo.FieldsMap[ks]; found { + panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks)) + } + e.addElem(ks, m.MapIndex(k), false) + } + } + } + for _, info := range sinfo.FieldsList { + if info.Inline == nil { + value = v.Field(info.Num) + } else { + value = v.FieldByIndex(info.Inline) + } + if info.OmitEmpty && isZero(value) { + continue + } + e.addElem(info.Key, value, info.MinSize) + } +} + +func isZero(v reflect.Value) bool { + switch v.Kind() { + case reflect.String: + return len(v.String()) == 0 + case reflect.Ptr, reflect.Interface: + return v.IsNil() + case reflect.Slice: + return v.Len() == 0 + case reflect.Map: + return v.Len() == 0 + 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.Bool: + return !v.Bool() + case reflect.Struct: + vt := v.Type() + if vt == typeTime { + return v.Interface().(time.Time).IsZero() + } + for i := 0; i < v.NumField(); i++ { + if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous { + continue // Private field + } + if !isZero(v.Field(i)) { + return false + } + } + return true + } + return false +} + +func (e *encoder) addSlice(v reflect.Value) { + vi := v.Interface() + if d, ok := vi.(D); ok { + for _, elem := range d { + e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) + } + return + } + if d, ok := vi.(RawD); ok { + for _, elem := range d { + e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) + } + return + } + l := v.Len() + et := v.Type().Elem() + if et == typeDocElem { + for i := 0; i < l; i++ { + elem := v.Index(i).Interface().(DocElem) + e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) + } + return + } + if et == typeRawDocElem { + for i := 0; i < l; i++ { + elem := v.Index(i).Interface().(RawDocElem) + e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) + } + return + } + for i := 0; i < l; i++ { + e.addElem(itoa(i), v.Index(i), false) + } +} + +// -------------------------------------------------------------------------- +// Marshaling of elements in a document. + +func (e *encoder) addElemName(kind byte, name string) { + e.addBytes(kind) + e.addBytes([]byte(name)...) + e.addBytes(0) +} + +func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { + + if !v.IsValid() { + e.addElemName(0x0A, name) + return + } + + if getter, ok := v.Interface().(Getter); ok { + getv, err := getter.GetBSON() + if err != nil { + panic(err) + } + e.addElem(name, reflect.ValueOf(getv), minSize) + return + } + + switch v.Kind() { + + case reflect.Interface: + e.addElem(name, v.Elem(), minSize) + + case reflect.Ptr: + e.addElem(name, v.Elem(), minSize) + + case reflect.String: + s := v.String() + switch v.Type() { + case typeObjectId: + if len(s) != 12 { + panic("ObjectIDs must be exactly 12 bytes long (got " + + strconv.Itoa(len(s)) + ")") + } + e.addElemName(0x07, name) + e.addBytes([]byte(s)...) + case typeSymbol: + e.addElemName(0x0E, name) + e.addStr(s) + case typeJSONNumber: + n := v.Interface().(json.Number) + if i, err := n.Int64(); err == nil { + e.addElemName(0x12, name) + e.addInt64(i) + } else if f, err := n.Float64(); err == nil { + e.addElemName(0x01, name) + e.addFloat64(f) + } else { + panic("failed to convert json.Number to a number: " + s) + } + default: + e.addElemName(0x02, name) + e.addStr(s) + } + + case reflect.Float32, reflect.Float64: + e.addElemName(0x01, name) + e.addFloat64(v.Float()) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + u := v.Uint() + if int64(u) < 0 { + panic("BSON has no uint64 type, and value is too large to fit correctly in an int64") + } else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) { + e.addElemName(0x10, name) + e.addInt32(int32(u)) + } else { + e.addElemName(0x12, name) + e.addInt64(int64(u)) + } + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch v.Type() { + case typeMongoTimestamp: + e.addElemName(0x11, name) + e.addInt64(v.Int()) + + case typeOrderKey: + if v.Int() == int64(MaxKey) { + e.addElemName(0x7F, name) + } else { + e.addElemName(0xFF, name) + } + + default: + i := v.Int() + if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 { + // It fits into an int32, encode as such. + e.addElemName(0x10, name) + e.addInt32(int32(i)) + } else { + e.addElemName(0x12, name) + e.addInt64(i) + } + } + + case reflect.Bool: + e.addElemName(0x08, name) + if v.Bool() { + e.addBytes(1) + } else { + e.addBytes(0) + } + + case reflect.Map: + e.addElemName(0x03, name) + e.addDoc(v) + + case reflect.Slice: + vt := v.Type() + et := vt.Elem() + if et.Kind() == reflect.Uint8 { + e.addElemName(0x05, name) + e.addBinary(0x00, v.Bytes()) + } else if et == typeDocElem || et == typeRawDocElem { + e.addElemName(0x03, name) + e.addDoc(v) + } else { + e.addElemName(0x04, name) + e.addDoc(v) + } + + case reflect.Array: + et := v.Type().Elem() + if et.Kind() == reflect.Uint8 { + e.addElemName(0x05, name) + if v.CanAddr() { + e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte)) + } else { + n := v.Len() + e.addInt32(int32(n)) + e.addBytes(0x00) + for i := 0; i < n; i++ { + el := v.Index(i) + e.addBytes(byte(el.Uint())) + } + } + } else { + e.addElemName(0x04, name) + e.addDoc(v) + } + + case reflect.Struct: + switch s := v.Interface().(type) { + + case Raw: + kind := s.Kind + if kind == 0x00 { + kind = 0x03 + } + if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F { + panic("Attempted to marshal empty Raw document") + } + e.addElemName(kind, name) + e.addBytes(s.Data...) + + case Binary: + e.addElemName(0x05, name) + e.addBinary(s.Kind, s.Data) + + case Decimal128: + e.addElemName(0x13, name) + e.addInt64(int64(s.l)) + e.addInt64(int64(s.h)) + + case DBPointer: + e.addElemName(0x0C, name) + e.addStr(s.Namespace) + if len(s.Id) != 12 { + panic("ObjectIDs must be exactly 12 bytes long (got " + + strconv.Itoa(len(s.Id)) + ")") + } + e.addBytes([]byte(s.Id)...) + + case RegEx: + e.addElemName(0x0B, name) + e.addCStr(s.Pattern) + e.addCStr(s.Options) + + case JavaScript: + if s.Scope == nil { + e.addElemName(0x0D, name) + e.addStr(s.Code) + } else { + e.addElemName(0x0F, name) + start := e.reserveInt32() + e.addStr(s.Code) + e.addDoc(reflect.ValueOf(s.Scope)) + e.setInt32(start, int32(len(e.out)-start)) + } + + case time.Time: + // MongoDB handles timestamps as milliseconds. + e.addElemName(0x09, name) + e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6)) + + case url.URL: + e.addElemName(0x02, name) + e.addStr(s.String()) + + case undefined: + e.addElemName(0x06, name) + + default: + e.addElemName(0x03, name) + e.addDoc(v) + } + + default: + panic("Can't marshal " + v.Type().String() + " in a BSON document") + } +} + +// -------------------------------------------------------------------------- +// Marshaling of base types. + +func (e *encoder) addBinary(subtype byte, v []byte) { + if subtype == 0x02 { + // Wonder how that brilliant idea came to life. Obsolete, luckily. + e.addInt32(int32(len(v) + 4)) + e.addBytes(subtype) + e.addInt32(int32(len(v))) + } else { + e.addInt32(int32(len(v))) + e.addBytes(subtype) + } + e.addBytes(v...) +} + +func (e *encoder) addStr(v string) { + e.addInt32(int32(len(v) + 1)) + e.addCStr(v) +} + +func (e *encoder) addCStr(v string) { + e.addBytes([]byte(v)...) + e.addBytes(0) +} + +func (e *encoder) reserveInt32() (pos int) { + pos = len(e.out) + e.addBytes(0, 0, 0, 0) + return pos +} + +func (e *encoder) setInt32(pos int, v int32) { + e.out[pos+0] = byte(v) + e.out[pos+1] = byte(v >> 8) + e.out[pos+2] = byte(v >> 16) + e.out[pos+3] = byte(v >> 24) +} + +func (e *encoder) addInt32(v int32) { + u := uint32(v) + e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24)) +} + +func (e *encoder) addInt64(v int64) { + u := uint64(v) + e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24), + byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56)) +} + +func (e *encoder) addFloat64(v float64) { + e.addInt64(int64(math.Float64bits(v))) +} + +func (e *encoder) addBytes(v ...byte) { + e.out = append(e.out, v...) +} diff --git a/vendor/gopkg.in/mgo.v2/bson/json.go b/vendor/gopkg.in/mgo.v2/bson/json.go new file mode 100644 index 000000000..09df8260a --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bson/json.go @@ -0,0 +1,380 @@ +package bson + +import ( + "bytes" + "encoding/base64" + "fmt" + "gopkg.in/mgo.v2/internal/json" + "strconv" + "time" +) + +// UnmarshalJSON unmarshals a JSON value that may hold non-standard +// syntax as defined in BSON's extended JSON specification. +func UnmarshalJSON(data []byte, value interface{}) error { + d := json.NewDecoder(bytes.NewBuffer(data)) + d.Extend(&jsonExt) + return d.Decode(value) +} + +// MarshalJSON marshals a JSON value that may hold non-standard +// syntax as defined in BSON's extended JSON specification. +func MarshalJSON(value interface{}) ([]byte, error) { + var buf bytes.Buffer + e := json.NewEncoder(&buf) + e.Extend(&jsonExt) + err := e.Encode(value) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// jdec is used internally by the JSON decoding functions +// so they may unmarshal functions without getting into endless +// recursion due to keyed objects. +func jdec(data []byte, value interface{}) error { + d := json.NewDecoder(bytes.NewBuffer(data)) + d.Extend(&funcExt) + return d.Decode(value) +} + +var jsonExt json.Extension +var funcExt json.Extension + +// TODO +// - Shell regular expressions ("/regexp/opts") + +func init() { + jsonExt.DecodeUnquotedKeys(true) + jsonExt.DecodeTrailingCommas(true) + + funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary") + jsonExt.DecodeKeyed("$binary", jdecBinary) + jsonExt.DecodeKeyed("$binaryFunc", jdecBinary) + jsonExt.EncodeType([]byte(nil), jencBinarySlice) + jsonExt.EncodeType(Binary{}, jencBinaryType) + + funcExt.DecodeFunc("ISODate", "$dateFunc", "S") + funcExt.DecodeFunc("new Date", "$dateFunc", "S") + jsonExt.DecodeKeyed("$date", jdecDate) + jsonExt.DecodeKeyed("$dateFunc", jdecDate) + jsonExt.EncodeType(time.Time{}, jencDate) + + funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i") + jsonExt.DecodeKeyed("$timestamp", jdecTimestamp) + jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp) + + funcExt.DecodeConst("undefined", Undefined) + + jsonExt.DecodeKeyed("$regex", jdecRegEx) + jsonExt.EncodeType(RegEx{}, jencRegEx) + + funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id") + jsonExt.DecodeKeyed("$oid", jdecObjectId) + jsonExt.DecodeKeyed("$oidFunc", jdecObjectId) + jsonExt.EncodeType(ObjectId(""), jencObjectId) + + funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id") + jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef) + + funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N") + jsonExt.DecodeKeyed("$numberLong", jdecNumberLong) + jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong) + jsonExt.EncodeType(int64(0), jencNumberLong) + jsonExt.EncodeType(int(0), jencInt) + + funcExt.DecodeConst("MinKey", MinKey) + funcExt.DecodeConst("MaxKey", MaxKey) + jsonExt.DecodeKeyed("$minKey", jdecMinKey) + jsonExt.DecodeKeyed("$maxKey", jdecMaxKey) + jsonExt.EncodeType(orderKey(0), jencMinMaxKey) + + jsonExt.DecodeKeyed("$undefined", jdecUndefined) + jsonExt.EncodeType(Undefined, jencUndefined) + + jsonExt.Extend(&funcExt) +} + +func fbytes(format string, args ...interface{}) []byte { + var buf bytes.Buffer + fmt.Fprintf(&buf, format, args...) + return buf.Bytes() +} + +func jdecBinary(data []byte) (interface{}, error) { + var v struct { + Binary []byte `json:"$binary"` + Type string `json:"$type"` + Func struct { + Binary []byte `json:"$binary"` + Type int64 `json:"$type"` + } `json:"$binaryFunc"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + + var binData []byte + var binKind int64 + if v.Type == "" && v.Binary == nil { + binData = v.Func.Binary + binKind = v.Func.Type + } else if v.Type == "" { + return v.Binary, nil + } else { + binData = v.Binary + binKind, err = strconv.ParseInt(v.Type, 0, 64) + if err != nil { + binKind = -1 + } + } + + if binKind == 0 { + return binData, nil + } + if binKind < 0 || binKind > 255 { + return nil, fmt.Errorf("invalid type in binary object: %s", data) + } + + return Binary{Kind: byte(binKind), Data: binData}, nil +} + +func jencBinarySlice(v interface{}) ([]byte, error) { + in := v.([]byte) + out := make([]byte, base64.StdEncoding.EncodedLen(len(in))) + base64.StdEncoding.Encode(out, in) + return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil +} + +func jencBinaryType(v interface{}) ([]byte, error) { + in := v.(Binary) + out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data))) + base64.StdEncoding.Encode(out, in.Data) + return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil +} + +const jdateFormat = "2006-01-02T15:04:05.999Z" + +func jdecDate(data []byte) (interface{}, error) { + var v struct { + S string `json:"$date"` + Func struct { + S string + } `json:"$dateFunc"` + } + _ = jdec(data, &v) + if v.S == "" { + v.S = v.Func.S + } + if v.S != "" { + for _, format := range []string{jdateFormat, "2006-01-02"} { + t, err := time.Parse(format, v.S) + if err == nil { + return t, nil + } + } + return nil, fmt.Errorf("cannot parse date: %q", v.S) + } + + var vn struct { + Date struct { + N int64 `json:"$numberLong,string"` + } `json:"$date"` + Func struct { + S int64 + } `json:"$dateFunc"` + } + err := jdec(data, &vn) + if err != nil { + return nil, fmt.Errorf("cannot parse date: %q", data) + } + n := vn.Date.N + if n == 0 { + n = vn.Func.S + } + return time.Unix(n/1000, n%1000*1e6).UTC(), nil +} + +func jencDate(v interface{}) ([]byte, error) { + t := v.(time.Time) + return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil +} + +func jdecTimestamp(data []byte) (interface{}, error) { + var v struct { + Func struct { + T int32 `json:"t"` + I int32 `json:"i"` + } `json:"$timestamp"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil +} + +func jencTimestamp(v interface{}) ([]byte, error) { + ts := uint64(v.(MongoTimestamp)) + return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil +} + +func jdecRegEx(data []byte) (interface{}, error) { + var v struct { + Regex string `json:"$regex"` + Options string `json:"$options"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + return RegEx{v.Regex, v.Options}, nil +} + +func jencRegEx(v interface{}) ([]byte, error) { + re := v.(RegEx) + type regex struct { + Regex string `json:"$regex"` + Options string `json:"$options"` + } + return json.Marshal(regex{re.Pattern, re.Options}) +} + +func jdecObjectId(data []byte) (interface{}, error) { + var v struct { + Id string `json:"$oid"` + Func struct { + Id string + } `json:"$oidFunc"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if v.Id == "" { + v.Id = v.Func.Id + } + return ObjectIdHex(v.Id), nil +} + +func jencObjectId(v interface{}) ([]byte, error) { + return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil +} + +func jdecDBRef(data []byte) (interface{}, error) { + // TODO Support unmarshaling $ref and $id into the input value. + var v struct { + Obj map[string]interface{} `json:"$dbrefFunc"` + } + // TODO Fix this. Must not be required. + v.Obj = make(map[string]interface{}) + err := jdec(data, &v) + if err != nil { + return nil, err + } + return v.Obj, nil +} + +func jdecNumberLong(data []byte) (interface{}, error) { + var v struct { + N int64 `json:"$numberLong,string"` + Func struct { + N int64 `json:",string"` + } `json:"$numberLongFunc"` + } + var vn struct { + N int64 `json:"$numberLong"` + Func struct { + N int64 + } `json:"$numberLongFunc"` + } + err := jdec(data, &v) + if err != nil { + err = jdec(data, &vn) + v.N = vn.N + v.Func.N = vn.Func.N + } + if err != nil { + return nil, err + } + if v.N != 0 { + return v.N, nil + } + return v.Func.N, nil +} + +func jencNumberLong(v interface{}) ([]byte, error) { + n := v.(int64) + f := `{"$numberLong":"%d"}` + if n <= 1<<53 { + f = `{"$numberLong":%d}` + } + return fbytes(f, n), nil +} + +func jencInt(v interface{}) ([]byte, error) { + n := v.(int) + f := `{"$numberLong":"%d"}` + if int64(n) <= 1<<53 { + f = `%d` + } + return fbytes(f, n), nil +} + +func jdecMinKey(data []byte) (interface{}, error) { + var v struct { + N int64 `json:"$minKey"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if v.N != 1 { + return nil, fmt.Errorf("invalid $minKey object: %s", data) + } + return MinKey, nil +} + +func jdecMaxKey(data []byte) (interface{}, error) { + var v struct { + N int64 `json:"$maxKey"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if v.N != 1 { + return nil, fmt.Errorf("invalid $maxKey object: %s", data) + } + return MaxKey, nil +} + +func jencMinMaxKey(v interface{}) ([]byte, error) { + switch v.(orderKey) { + case MinKey: + return []byte(`{"$minKey":1}`), nil + case MaxKey: + return []byte(`{"$maxKey":1}`), nil + } + panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v)) +} + +func jdecUndefined(data []byte) (interface{}, error) { + var v struct { + B bool `json:"$undefined"` + } + err := jdec(data, &v) + if err != nil { + return nil, err + } + if !v.B { + return nil, fmt.Errorf("invalid $undefined object: %s", data) + } + return Undefined, nil +} + +func jencUndefined(v interface{}) ([]byte, error) { + return []byte(`{"$undefined":true}`), nil +} diff --git a/vendor/gopkg.in/mgo.v2/bulk.go b/vendor/gopkg.in/mgo.v2/bulk.go new file mode 100644 index 000000000..072a5206a --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/bulk.go @@ -0,0 +1,351 @@ +package mgo + +import ( + "bytes" + "sort" + + "gopkg.in/mgo.v2/bson" +) + +// Bulk represents an operation that can be prepared with several +// orthogonal changes before being delivered to the server. +// +// MongoDB servers older than version 2.6 do not have proper support for bulk +// operations, so the driver attempts to map its API as much as possible into +// the functionality that works. In particular, in those releases updates and +// removals are sent individually, and inserts are sent in bulk but have +// suboptimal error reporting compared to more recent versions of the server. +// See the documentation of BulkErrorCase for details on that. +// +// Relevant documentation: +// +// http://blog.mongodb.org/post/84922794768/mongodbs-new-bulk-api +// +type Bulk struct { + c *Collection + opcount int + actions []bulkAction + ordered bool +} + +type bulkOp int + +const ( + bulkInsert bulkOp = iota + 1 + bulkUpdate + bulkUpdateAll + bulkRemove +) + +type bulkAction struct { + op bulkOp + docs []interface{} + idxs []int +} + +type bulkUpdateOp []interface{} +type bulkDeleteOp []interface{} + +// BulkResult holds the results for a bulk operation. +type BulkResult struct { + Matched int + Modified int // Available only for MongoDB 2.6+ + + // Be conservative while we understand exactly how to report these + // results in a useful and convenient way, and also how to emulate + // them with prior servers. + private bool +} + +// BulkError holds an error returned from running a Bulk operation. +// Individual errors may be obtained and inspected via the Cases method. +type BulkError struct { + ecases []BulkErrorCase +} + +func (e *BulkError) Error() string { + if len(e.ecases) == 0 { + return "invalid BulkError instance: no errors" + } + if len(e.ecases) == 1 { + return e.ecases[0].Err.Error() + } + msgs := make([]string, 0, len(e.ecases)) + seen := make(map[string]bool) + for _, ecase := range e.ecases { + msg := ecase.Err.Error() + if !seen[msg] { + seen[msg] = true + msgs = append(msgs, msg) + } + } + if len(msgs) == 1 { + return msgs[0] + } + var buf bytes.Buffer + buf.WriteString("multiple errors in bulk operation:\n") + for _, msg := range msgs { + buf.WriteString(" - ") + buf.WriteString(msg) + buf.WriteByte('\n') + } + return buf.String() +} + +type bulkErrorCases []BulkErrorCase + +func (slice bulkErrorCases) Len() int { return len(slice) } +func (slice bulkErrorCases) Less(i, j int) bool { return slice[i].Index < slice[j].Index } +func (slice bulkErrorCases) Swap(i, j int) { slice[i], slice[j] = slice[j], slice[i] } + +// BulkErrorCase holds an individual error found while attempting a single change +// within a bulk operation, and the position in which it was enqueued. +// +// MongoDB servers older than version 2.6 do not have proper support for bulk +// operations, so the driver attempts to map its API as much as possible into +// the functionality that works. In particular, only the last error is reported +// for bulk inserts and without any positional information, so the Index +// field is set to -1 in these cases. +type BulkErrorCase struct { + Index int // Position of operation that failed, or -1 if unknown. + Err error +} + +// Cases returns all individual errors found while attempting the requested changes. +// +// See the documentation of BulkErrorCase for limitations in older MongoDB releases. +func (e *BulkError) Cases() []BulkErrorCase { + return e.ecases +} + +// Bulk returns a value to prepare the execution of a bulk operation. +func (c *Collection) Bulk() *Bulk { + return &Bulk{c: c, ordered: true} +} + +// Unordered puts the bulk operation in unordered mode. +// +// In unordered mode the indvidual operations may be sent +// out of order, which means latter operations may proceed +// even if prior ones have failed. +func (b *Bulk) Unordered() { + b.ordered = false +} + +func (b *Bulk) action(op bulkOp, opcount int) *bulkAction { + var action *bulkAction + if len(b.actions) > 0 && b.actions[len(b.actions)-1].op == op { + action = &b.actions[len(b.actions)-1] + } else if !b.ordered { + for i := range b.actions { + if b.actions[i].op == op { + action = &b.actions[i] + break + } + } + } + if action == nil { + b.actions = append(b.actions, bulkAction{op: op}) + action = &b.actions[len(b.actions)-1] + } + for i := 0; i < opcount; i++ { + action.idxs = append(action.idxs, b.opcount) + b.opcount++ + } + return action +} + +// Insert queues up the provided documents for insertion. +func (b *Bulk) Insert(docs ...interface{}) { + action := b.action(bulkInsert, len(docs)) + action.docs = append(action.docs, docs...) +} + +// Remove queues up the provided selectors for removing matching documents. +// Each selector will remove only a single matching document. +func (b *Bulk) Remove(selectors ...interface{}) { + action := b.action(bulkRemove, len(selectors)) + for _, selector := range selectors { + if selector == nil { + selector = bson.D{} + } + action.docs = append(action.docs, &deleteOp{ + Collection: b.c.FullName, + Selector: selector, + Flags: 1, + Limit: 1, + }) + } +} + +// RemoveAll queues up the provided selectors for removing all matching documents. +// Each selector will remove all matching documents. +func (b *Bulk) RemoveAll(selectors ...interface{}) { + action := b.action(bulkRemove, len(selectors)) + for _, selector := range selectors { + if selector == nil { + selector = bson.D{} + } + action.docs = append(action.docs, &deleteOp{ + Collection: b.c.FullName, + Selector: selector, + Flags: 0, + Limit: 0, + }) + } +} + +// Update queues up the provided pairs of updating instructions. +// The first element of each pair selects which documents must be +// updated, and the second element defines how to update it. +// Each pair matches exactly one document for updating at most. +func (b *Bulk) Update(pairs ...interface{}) { + if len(pairs)%2 != 0 { + panic("Bulk.Update requires an even number of parameters") + } + action := b.action(bulkUpdate, len(pairs)/2) + for i := 0; i < len(pairs); i += 2 { + selector := pairs[i] + if selector == nil { + selector = bson.D{} + } + action.docs = append(action.docs, &updateOp{ + Collection: b.c.FullName, + Selector: selector, + Update: pairs[i+1], + }) + } +} + +// UpdateAll queues up the provided pairs of updating instructions. +// The first element of each pair selects which documents must be +// updated, and the second element defines how to update it. +// Each pair updates all documents matching the selector. +func (b *Bulk) UpdateAll(pairs ...interface{}) { + if len(pairs)%2 != 0 { + panic("Bulk.UpdateAll requires an even number of parameters") + } + action := b.action(bulkUpdate, len(pairs)/2) + for i := 0; i < len(pairs); i += 2 { + selector := pairs[i] + if selector == nil { + selector = bson.D{} + } + action.docs = append(action.docs, &updateOp{ + Collection: b.c.FullName, + Selector: selector, + Update: pairs[i+1], + Flags: 2, + Multi: true, + }) + } +} + +// Upsert queues up the provided pairs of upserting instructions. +// The first element of each pair selects which documents must be +// updated, and the second element defines how to update it. +// Each pair matches exactly one document for updating at most. +func (b *Bulk) Upsert(pairs ...interface{}) { + if len(pairs)%2 != 0 { + panic("Bulk.Update requires an even number of parameters") + } + action := b.action(bulkUpdate, len(pairs)/2) + for i := 0; i < len(pairs); i += 2 { + selector := pairs[i] + if selector == nil { + selector = bson.D{} + } + action.docs = append(action.docs, &updateOp{ + Collection: b.c.FullName, + Selector: selector, + Update: pairs[i+1], + Flags: 1, + Upsert: true, + }) + } +} + +// Run runs all the operations queued up. +// +// If an error is reported on an unordered bulk operation, the error value may +// be an aggregation of all issues observed. As an exception to that, Insert +// operations running on MongoDB versions prior to 2.6 will report the last +// error only due to a limitation in the wire protocol. +func (b *Bulk) Run() (*BulkResult, error) { + var result BulkResult + var berr BulkError + var failed bool + for i := range b.actions { + action := &b.actions[i] + var ok bool + switch action.op { + case bulkInsert: + ok = b.runInsert(action, &result, &berr) + case bulkUpdate: + ok = b.runUpdate(action, &result, &berr) + case bulkRemove: + ok = b.runRemove(action, &result, &berr) + default: + panic("unknown bulk operation") + } + if !ok { + failed = true + if b.ordered { + break + } + } + } + if failed { + sort.Sort(bulkErrorCases(berr.ecases)) + return nil, &berr + } + return &result, nil +} + +func (b *Bulk) runInsert(action *bulkAction, result *BulkResult, berr *BulkError) bool { + op := &insertOp{b.c.FullName, action.docs, 0} + if !b.ordered { + op.flags = 1 // ContinueOnError + } + lerr, err := b.c.writeOp(op, b.ordered) + return b.checkSuccess(action, berr, lerr, err) +} + +func (b *Bulk) runUpdate(action *bulkAction, result *BulkResult, berr *BulkError) bool { + lerr, err := b.c.writeOp(bulkUpdateOp(action.docs), b.ordered) + if lerr != nil { + result.Matched += lerr.N + result.Modified += lerr.modified + } + return b.checkSuccess(action, berr, lerr, err) +} + +func (b *Bulk) runRemove(action *bulkAction, result *BulkResult, berr *BulkError) bool { + lerr, err := b.c.writeOp(bulkDeleteOp(action.docs), b.ordered) + if lerr != nil { + result.Matched += lerr.N + result.Modified += lerr.modified + } + return b.checkSuccess(action, berr, lerr, err) +} + +func (b *Bulk) checkSuccess(action *bulkAction, berr *BulkError, lerr *LastError, err error) bool { + if lerr != nil && len(lerr.ecases) > 0 { + for i := 0; i < len(lerr.ecases); i++ { + // Map back from the local error index into the visible one. + ecase := lerr.ecases[i] + idx := ecase.Index + if idx >= 0 { + idx = action.idxs[idx] + } + berr.ecases = append(berr.ecases, BulkErrorCase{idx, ecase.Err}) + } + return false + } else if err != nil { + for i := 0; i < len(action.idxs); i++ { + berr.ecases = append(berr.ecases, BulkErrorCase{action.idxs[i], err}) + } + return false + } + return true +} diff --git a/vendor/gopkg.in/mgo.v2/cluster.go b/vendor/gopkg.in/mgo.v2/cluster.go new file mode 100644 index 000000000..c3bf8b013 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/cluster.go @@ -0,0 +1,682 @@ +// mgo - MongoDB driver for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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 mgo + +import ( + "errors" + "fmt" + "net" + "strconv" + "strings" + "sync" + "time" + + "gopkg.in/mgo.v2/bson" +) + +// --------------------------------------------------------------------------- +// Mongo cluster encapsulation. +// +// A cluster enables the communication with one or more servers participating +// in a mongo cluster. This works with individual servers, a replica set, +// a replica pair, one or multiple mongos routers, etc. + +type mongoCluster struct { + sync.RWMutex + serverSynced sync.Cond + userSeeds []string + dynaSeeds []string + servers mongoServers + masters mongoServers + references int + syncing bool + direct bool + failFast bool + syncCount uint + setName string + cachedIndex map[string]bool + sync chan bool + dial dialer +} + +func newCluster(userSeeds []string, direct, failFast bool, dial dialer, setName string) *mongoCluster { + cluster := &mongoCluster{ + userSeeds: userSeeds, + references: 1, + direct: direct, + failFast: failFast, + dial: dial, + setName: setName, + } + cluster.serverSynced.L = cluster.RWMutex.RLocker() + cluster.sync = make(chan bool, 1) + stats.cluster(+1) + go cluster.syncServersLoop() + return cluster +} + +// Acquire increases the reference count for the cluster. +func (cluster *mongoCluster) Acquire() { + cluster.Lock() + cluster.references++ + debugf("Cluster %p acquired (refs=%d)", cluster, cluster.references) + cluster.Unlock() +} + +// Release decreases the reference count for the cluster. Once +// it reaches zero, all servers will be closed. +func (cluster *mongoCluster) Release() { + cluster.Lock() + if cluster.references == 0 { + panic("cluster.Release() with references == 0") + } + cluster.references-- + debugf("Cluster %p released (refs=%d)", cluster, cluster.references) + if cluster.references == 0 { + for _, server := range cluster.servers.Slice() { + server.Close() + } + // Wake up the sync loop so it can die. + cluster.syncServers() + stats.cluster(-1) + } + cluster.Unlock() +} + +func (cluster *mongoCluster) LiveServers() (servers []string) { + cluster.RLock() + for _, serv := range cluster.servers.Slice() { + servers = append(servers, serv.Addr) + } + cluster.RUnlock() + return servers +} + +func (cluster *mongoCluster) removeServer(server *mongoServer) { + cluster.Lock() + cluster.masters.Remove(server) + other := cluster.servers.Remove(server) + cluster.Unlock() + if other != nil { + other.Close() + log("Removed server ", server.Addr, " from cluster.") + } + server.Close() +} + +type isMasterResult struct { + IsMaster bool + Secondary bool + Primary string + Hosts []string + Passives []string + Tags bson.D + Msg string + SetName string `bson:"setName"` + MaxWireVersion int `bson:"maxWireVersion"` +} + +func (cluster *mongoCluster) isMaster(socket *mongoSocket, result *isMasterResult) error { + // Monotonic let's it talk to a slave and still hold the socket. + session := newSession(Monotonic, cluster, 10*time.Second) + session.setSocket(socket) + err := session.Run("ismaster", result) + session.Close() + return err +} + +type possibleTimeout interface { + Timeout() bool +} + +var syncSocketTimeout = 5 * time.Second + +func (cluster *mongoCluster) syncServer(server *mongoServer) (info *mongoServerInfo, hosts []string, err error) { + var syncTimeout time.Duration + if raceDetector { + // This variable is only ever touched by tests. + globalMutex.Lock() + syncTimeout = syncSocketTimeout + globalMutex.Unlock() + } else { + syncTimeout = syncSocketTimeout + } + + addr := server.Addr + log("SYNC Processing ", addr, "...") + + // Retry a few times to avoid knocking a server down for a hiccup. + var result isMasterResult + var tryerr error + for retry := 0; ; retry++ { + if retry == 3 || retry == 1 && cluster.failFast { + return nil, nil, tryerr + } + if retry > 0 { + // Don't abuse the server needlessly if there's something actually wrong. + if err, ok := tryerr.(possibleTimeout); ok && err.Timeout() { + // Give a chance for waiters to timeout as well. + cluster.serverSynced.Broadcast() + } + time.Sleep(syncShortDelay) + } + + // It's not clear what would be a good timeout here. Is it + // better to wait longer or to retry? + socket, _, err := server.AcquireSocket(0, syncTimeout) + if err != nil { + tryerr = err + logf("SYNC Failed to get socket to %s: %v", addr, err) + continue + } + err = cluster.isMaster(socket, &result) + socket.Release() + if err != nil { + tryerr = err + logf("SYNC Command 'ismaster' to %s failed: %v", addr, err) + continue + } + debugf("SYNC Result of 'ismaster' from %s: %#v", addr, result) + break + } + + if cluster.setName != "" && result.SetName != cluster.setName { + logf("SYNC Server %s is not a member of replica set %q", addr, cluster.setName) + return nil, nil, fmt.Errorf("server %s is not a member of replica set %q", addr, cluster.setName) + } + + if result.IsMaster { + debugf("SYNC %s is a master.", addr) + if !server.info.Master { + // Made an incorrect assumption above, so fix stats. + stats.conn(-1, false) + stats.conn(+1, true) + } + } else if result.Secondary { + debugf("SYNC %s is a slave.", addr) + } else if cluster.direct { + logf("SYNC %s in unknown state. Pretending it's a slave due to direct connection.", addr) + } else { + logf("SYNC %s is neither a master nor a slave.", addr) + // Let stats track it as whatever was known before. + return nil, nil, errors.New(addr + " is not a master nor slave") + } + + info = &mongoServerInfo{ + Master: result.IsMaster, + Mongos: result.Msg == "isdbgrid", + Tags: result.Tags, + SetName: result.SetName, + MaxWireVersion: result.MaxWireVersion, + } + + hosts = make([]string, 0, 1+len(result.Hosts)+len(result.Passives)) + if result.Primary != "" { + // First in the list to speed up master discovery. + hosts = append(hosts, result.Primary) + } + hosts = append(hosts, result.Hosts...) + hosts = append(hosts, result.Passives...) + + debugf("SYNC %s knows about the following peers: %#v", addr, hosts) + return info, hosts, nil +} + +type syncKind bool + +const ( + completeSync syncKind = true + partialSync syncKind = false +) + +func (cluster *mongoCluster) addServer(server *mongoServer, info *mongoServerInfo, syncKind syncKind) { + cluster.Lock() + current := cluster.servers.Search(server.ResolvedAddr) + if current == nil { + if syncKind == partialSync { + cluster.Unlock() + server.Close() + log("SYNC Discarding unknown server ", server.Addr, " due to partial sync.") + return + } + cluster.servers.Add(server) + if info.Master { + cluster.masters.Add(server) + log("SYNC Adding ", server.Addr, " to cluster as a master.") + } else { + log("SYNC Adding ", server.Addr, " to cluster as a slave.") + } + } else { + if server != current { + panic("addServer attempting to add duplicated server") + } + if server.Info().Master != info.Master { + if info.Master { + log("SYNC Server ", server.Addr, " is now a master.") + cluster.masters.Add(server) + } else { + log("SYNC Server ", server.Addr, " is now a slave.") + cluster.masters.Remove(server) + } + } + } + server.SetInfo(info) + debugf("SYNC Broadcasting availability of server %s", server.Addr) + cluster.serverSynced.Broadcast() + cluster.Unlock() +} + +func (cluster *mongoCluster) getKnownAddrs() []string { + cluster.RLock() + max := len(cluster.userSeeds) + len(cluster.dynaSeeds) + cluster.servers.Len() + seen := make(map[string]bool, max) + known := make([]string, 0, max) + + add := func(addr string) { + if _, found := seen[addr]; !found { + seen[addr] = true + known = append(known, addr) + } + } + + for _, addr := range cluster.userSeeds { + add(addr) + } + for _, addr := range cluster.dynaSeeds { + add(addr) + } + for _, serv := range cluster.servers.Slice() { + add(serv.Addr) + } + cluster.RUnlock() + + return known +} + +// syncServers injects a value into the cluster.sync channel to force +// an iteration of the syncServersLoop function. +func (cluster *mongoCluster) syncServers() { + select { + case cluster.sync <- true: + default: + } +} + +// How long to wait for a checkup of the cluster topology if nothing +// else kicks a synchronization before that. +const syncServersDelay = 30 * time.Second +const syncShortDelay = 500 * time.Millisecond + +// syncServersLoop loops while the cluster is alive to keep its idea of +// the server topology up-to-date. It must be called just once from +// newCluster. The loop iterates once syncServersDelay has passed, or +// if somebody injects a value into the cluster.sync channel to force a +// synchronization. A loop iteration will contact all servers in +// parallel, ask them about known peers and their own role within the +// cluster, and then attempt to do the same with all the peers +// retrieved. +func (cluster *mongoCluster) syncServersLoop() { + for { + debugf("SYNC Cluster %p is starting a sync loop iteration.", cluster) + + cluster.Lock() + if cluster.references == 0 { + cluster.Unlock() + break + } + cluster.references++ // Keep alive while syncing. + direct := cluster.direct + cluster.Unlock() + + cluster.syncServersIteration(direct) + + // We just synchronized, so consume any outstanding requests. + select { + case <-cluster.sync: + default: + } + + cluster.Release() + + // Hold off before allowing another sync. No point in + // burning CPU looking for down servers. + if !cluster.failFast { + time.Sleep(syncShortDelay) + } + + cluster.Lock() + if cluster.references == 0 { + cluster.Unlock() + break + } + cluster.syncCount++ + // Poke all waiters so they have a chance to timeout or + // restart syncing if they wish to. + cluster.serverSynced.Broadcast() + // Check if we have to restart immediately either way. + restart := !direct && cluster.masters.Empty() || cluster.servers.Empty() + cluster.Unlock() + + if restart { + log("SYNC No masters found. Will synchronize again.") + time.Sleep(syncShortDelay) + continue + } + + debugf("SYNC Cluster %p waiting for next requested or scheduled sync.", cluster) + + // Hold off until somebody explicitly requests a synchronization + // or it's time to check for a cluster topology change again. + select { + case <-cluster.sync: + case <-time.After(syncServersDelay): + } + } + debugf("SYNC Cluster %p is stopping its sync loop.", cluster) +} + +func (cluster *mongoCluster) server(addr string, tcpaddr *net.TCPAddr) *mongoServer { + cluster.RLock() + server := cluster.servers.Search(tcpaddr.String()) + cluster.RUnlock() + if server != nil { + return server + } + return newServer(addr, tcpaddr, cluster.sync, cluster.dial) +} + +func resolveAddr(addr string) (*net.TCPAddr, error) { + // Simple cases that do not need actual resolution. Works with IPv4 and v6. + if host, port, err := net.SplitHostPort(addr); err == nil { + if port, _ := strconv.Atoi(port); port > 0 { + zone := "" + if i := strings.LastIndex(host, "%"); i >= 0 { + zone = host[i+1:] + host = host[:i] + } + ip := net.ParseIP(host) + if ip != nil { + return &net.TCPAddr{IP: ip, Port: port, Zone: zone}, nil + } + } + } + + // Attempt to resolve IPv4 and v6 concurrently. + addrChan := make(chan *net.TCPAddr, 2) + for _, network := range []string{"udp4", "udp6"} { + network := network + go func() { + // The unfortunate UDP dialing hack allows having a timeout on address resolution. + conn, err := net.DialTimeout(network, addr, 10*time.Second) + if err != nil { + addrChan <- nil + } else { + addrChan <- (*net.TCPAddr)(conn.RemoteAddr().(*net.UDPAddr)) + conn.Close() + } + }() + } + + // Wait for the result of IPv4 and v6 resolution. Use IPv4 if available. + tcpaddr := <-addrChan + if tcpaddr == nil || len(tcpaddr.IP) != 4 { + var timeout <-chan time.Time + if tcpaddr != nil { + // Don't wait too long if an IPv6 address is known. + timeout = time.After(50 * time.Millisecond) + } + select { + case <-timeout: + case tcpaddr2 := <-addrChan: + if tcpaddr == nil || tcpaddr2 != nil { + // It's an IPv4 address or the only known address. Use it. + tcpaddr = tcpaddr2 + } + } + } + + if tcpaddr == nil { + log("SYNC Failed to resolve server address: ", addr) + return nil, errors.New("failed to resolve server address: " + addr) + } + if tcpaddr.String() != addr { + debug("SYNC Address ", addr, " resolved as ", tcpaddr.String()) + } + return tcpaddr, nil +} + +type pendingAdd struct { + server *mongoServer + info *mongoServerInfo +} + +func (cluster *mongoCluster) syncServersIteration(direct bool) { + log("SYNC Starting full topology synchronization...") + + var wg sync.WaitGroup + var m sync.Mutex + notYetAdded := make(map[string]pendingAdd) + addIfFound := make(map[string]bool) + seen := make(map[string]bool) + syncKind := partialSync + + var spawnSync func(addr string, byMaster bool) + spawnSync = func(addr string, byMaster bool) { + wg.Add(1) + go func() { + defer wg.Done() + + tcpaddr, err := resolveAddr(addr) + if err != nil { + log("SYNC Failed to start sync of ", addr, ": ", err.Error()) + return + } + resolvedAddr := tcpaddr.String() + + m.Lock() + if byMaster { + if pending, ok := notYetAdded[resolvedAddr]; ok { + delete(notYetAdded, resolvedAddr) + m.Unlock() + cluster.addServer(pending.server, pending.info, completeSync) + return + } + addIfFound[resolvedAddr] = true + } + if seen[resolvedAddr] { + m.Unlock() + return + } + seen[resolvedAddr] = true + m.Unlock() + + server := cluster.server(addr, tcpaddr) + info, hosts, err := cluster.syncServer(server) + if err != nil { + cluster.removeServer(server) + return + } + + m.Lock() + add := direct || info.Master || addIfFound[resolvedAddr] + if add { + syncKind = completeSync + } else { + notYetAdded[resolvedAddr] = pendingAdd{server, info} + } + m.Unlock() + if add { + cluster.addServer(server, info, completeSync) + } + if !direct { + for _, addr := range hosts { + spawnSync(addr, info.Master) + } + } + }() + } + + knownAddrs := cluster.getKnownAddrs() + for _, addr := range knownAddrs { + spawnSync(addr, false) + } + wg.Wait() + + if syncKind == completeSync { + logf("SYNC Synchronization was complete (got data from primary).") + for _, pending := range notYetAdded { + cluster.removeServer(pending.server) + } + } else { + logf("SYNC Synchronization was partial (cannot talk to primary).") + for _, pending := range notYetAdded { + cluster.addServer(pending.server, pending.info, partialSync) + } + } + + cluster.Lock() + mastersLen := cluster.masters.Len() + logf("SYNC Synchronization completed: %d master(s) and %d slave(s) alive.", mastersLen, cluster.servers.Len()-mastersLen) + + // Update dynamic seeds, but only if we have any good servers. Otherwise, + // leave them alone for better chances of a successful sync in the future. + if syncKind == completeSync { + dynaSeeds := make([]string, cluster.servers.Len()) + for i, server := range cluster.servers.Slice() { + dynaSeeds[i] = server.Addr + } + cluster.dynaSeeds = dynaSeeds + debugf("SYNC New dynamic seeds: %#v\n", dynaSeeds) + } + cluster.Unlock() +} + +// AcquireSocket returns a socket to a server in the cluster. If slaveOk is +// true, it will attempt to return a socket to a slave server. If it is +// false, the socket will necessarily be to a master server. +func (cluster *mongoCluster) AcquireSocket(mode Mode, slaveOk bool, syncTimeout time.Duration, socketTimeout time.Duration, serverTags []bson.D, poolLimit int) (s *mongoSocket, err error) { + var started time.Time + var syncCount uint + warnedLimit := false + for { + cluster.RLock() + for { + mastersLen := cluster.masters.Len() + slavesLen := cluster.servers.Len() - mastersLen + debugf("Cluster has %d known masters and %d known slaves.", mastersLen, slavesLen) + if mastersLen > 0 && !(slaveOk && mode == Secondary) || slavesLen > 0 && slaveOk { + break + } + if mastersLen > 0 && mode == Secondary && cluster.masters.HasMongos() { + break + } + if started.IsZero() { + // Initialize after fast path above. + started = time.Now() + syncCount = cluster.syncCount + } else if syncTimeout != 0 && started.Before(time.Now().Add(-syncTimeout)) || cluster.failFast && cluster.syncCount != syncCount { + cluster.RUnlock() + return nil, errors.New("no reachable servers") + } + log("Waiting for servers to synchronize...") + cluster.syncServers() + + // Remember: this will release and reacquire the lock. + cluster.serverSynced.Wait() + } + + var server *mongoServer + if slaveOk { + server = cluster.servers.BestFit(mode, serverTags) + } else { + server = cluster.masters.BestFit(mode, nil) + } + cluster.RUnlock() + + if server == nil { + // Must have failed the requested tags. Sleep to avoid spinning. + time.Sleep(1e8) + continue + } + + s, abended, err := server.AcquireSocket(poolLimit, socketTimeout) + if err == errPoolLimit { + if !warnedLimit { + warnedLimit = true + log("WARNING: Per-server connection limit reached.") + } + time.Sleep(100 * time.Millisecond) + continue + } + if err != nil { + cluster.removeServer(server) + cluster.syncServers() + continue + } + if abended && !slaveOk { + var result isMasterResult + err := cluster.isMaster(s, &result) + if err != nil || !result.IsMaster { + logf("Cannot confirm server %s as master (%v)", server.Addr, err) + s.Release() + cluster.syncServers() + time.Sleep(100 * time.Millisecond) + continue + } + } + return s, nil + } + panic("unreached") +} + +func (cluster *mongoCluster) CacheIndex(cacheKey string, exists bool) { + cluster.Lock() + if cluster.cachedIndex == nil { + cluster.cachedIndex = make(map[string]bool) + } + if exists { + cluster.cachedIndex[cacheKey] = true + } else { + delete(cluster.cachedIndex, cacheKey) + } + cluster.Unlock() +} + +func (cluster *mongoCluster) HasCachedIndex(cacheKey string) (result bool) { + cluster.RLock() + if cluster.cachedIndex != nil { + result = cluster.cachedIndex[cacheKey] + } + cluster.RUnlock() + return +} + +func (cluster *mongoCluster) ResetIndexCache() { + cluster.Lock() + cluster.cachedIndex = make(map[string]bool) + cluster.Unlock() +} diff --git a/vendor/gopkg.in/mgo.v2/doc.go b/vendor/gopkg.in/mgo.v2/doc.go new file mode 100644 index 000000000..859fd9b8d --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/doc.go @@ -0,0 +1,31 @@ +// Package mgo offers a rich MongoDB driver for Go. +// +// Details about the mgo project (pronounced as "mango") are found +// in its web page: +// +// http://labix.org/mgo +// +// Usage of the driver revolves around the concept of sessions. To +// get started, obtain a session using the Dial function: +// +// session, err := mgo.Dial(url) +// +// This will establish one or more connections with the cluster of +// servers defined by the url parameter. From then on, the cluster +// may be queried with multiple consistency rules (see SetMode) and +// documents retrieved with statements such as: +// +// c := session.DB(database).C(collection) +// err := c.Find(query).One(&result) +// +// New sessions are typically created by calling session.Copy on the +// initial session obtained at dial time. These new sessions will share +// the same cluster information and connection pool, and may be easily +// handed into other methods and functions for organizing logic. +// Every session created must have its Close method called at the end +// of its life time, so its resources may be put back in the pool or +// collected, depending on the case. +// +// For more details, see the documentation for the types and methods. +// +package mgo diff --git a/vendor/gopkg.in/mgo.v2/gridfs.go b/vendor/gopkg.in/mgo.v2/gridfs.go new file mode 100644 index 000000000..421472095 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/gridfs.go @@ -0,0 +1,761 @@ +// mgo - MongoDB driver for Go +// +// Copyright (c) 2010-2012 - Gustavo Niemeyer +// +// 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. +// +// 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 mgo + +import ( + "crypto/md5" + "encoding/hex" + "errors" + "hash" + "io" + "os" + "sync" + "time" + + "gopkg.in/mgo.v2/bson" +) + +type GridFS struct { + Files *Collection + Chunks *Collection +} + +type gfsFileMode int + +const ( + gfsClosed gfsFileMode = 0 + gfsReading gfsFileMode = 1 + gfsWriting gfsFileMode = 2 +) + +type GridFile struct { + m sync.Mutex + c sync.Cond + gfs *GridFS + mode gfsFileMode + err error + + chunk int + offset int64 + + wpending int + wbuf []byte + wsum hash.Hash + + rbuf []byte + rcache *gfsCachedChunk + + doc gfsFile +} + +type gfsFile struct { + Id interface{} "_id" + ChunkSize int "chunkSize" + UploadDate time.Time "uploadDate" + Length int64 ",minsize" + MD5 string + Filename string ",omitempty" + ContentType string "contentType,omitempty" + Metadata *bson.Raw ",omitempty" +} + +type gfsChunk struct { + Id interface{} "_id" + FilesId interface{} "files_id" + N int + Data []byte +} + +type gfsCachedChunk struct { + wait sync.Mutex + n int + data []byte + err error +} + +func newGridFS(db *Database, prefix string) *GridFS { + return &GridFS{db.C(prefix + ".files"), db.C(prefix + ".chunks")} +} + +func (gfs *GridFS) newFile() *GridFile { + file := &GridFile{gfs: gfs} + file.c.L = &file.m + //runtime.SetFinalizer(file, finalizeFile) + return file +} + +func finalizeFile(file *GridFile) { + file.Close() +} + +// Create creates a new file with the provided name in the GridFS. If the file +// name already exists, a new version will be inserted with an up-to-date +// uploadDate that will cause it to be atomically visible to the Open and +// OpenId methods. If the file name is not important, an empty name may be +// provided and the file Id used instead. +// +// It's important to Close files whether they are being written to +// or read from, and to check the err result to ensure the operation +// completed successfully. +// +// A simple example inserting a new file: +// +// func check(err error) { +// if err != nil { +// panic(err.String()) +// } +// } +// file, err := db.GridFS("fs").Create("myfile.txt") +// check(err) +// n, err := file.Write([]byte("Hello world!")) +// check(err) +// err = file.Close() +// check(err) +// fmt.Printf("%d bytes written\n", n) +// +// The io.Writer interface is implemented by *GridFile and may be used to +// help on the file creation. For example: +// +// file, err := db.GridFS("fs").Create("myfile.txt") +// check(err) +// messages, err := os.Open("/var/log/messages") +// check(err) +// defer messages.Close() +// err = io.Copy(file, messages) +// check(err) +// err = file.Close() +// check(err) +// +func (gfs *GridFS) Create(name string) (file *GridFile, err error) { + file = gfs.newFile() + file.mode = gfsWriting + file.wsum = md5.New() + file.doc = gfsFile{Id: bson.NewObjectId(), ChunkSize: 255 * 1024, Filename: name} + return +} + +// OpenId returns the file with the provided id, for reading. +// If the file isn't found, err will be set to mgo.ErrNotFound. +// +// It's important to Close files whether they are being written to +// or read from, and to check the err result to ensure the operation +// completed successfully. +// +// The following example will print the first 8192 bytes from the file: +// +// func check(err error) { +// if err != nil { +// panic(err.String()) +// } +// } +// file, err := db.GridFS("fs").OpenId(objid) +// check(err) +// b := make([]byte, 8192) +// n, err := file.Read(b) +// check(err) +// fmt.Println(string(b)) +// check(err) +// err = file.Close() +// check(err) +// fmt.Printf("%d bytes read\n", n) +// +// The io.Reader interface is implemented by *GridFile and may be used to +// deal with it. As an example, the following snippet will dump the whole +// file into the standard output: +// +// file, err := db.GridFS("fs").OpenId(objid) +// check(err) +// err = io.Copy(os.Stdout, file) +// check(err) +// err = file.Close() +// check(err) +// +func (gfs *GridFS) OpenId(id interface{}) (file *GridFile, err error) { + var doc gfsFile + err = gfs.Files.Find(bson.M{"_id": id}).One(&doc) + if err != nil { + return + } + file = gfs.newFile() + file.mode = gfsReading + file.doc = doc + return +} + +// Open returns the most recently uploaded file with the provided +// name, for reading. If the file isn't found, err will be set +// to mgo.ErrNotFound. +// +// It's important to Close files whether they are being written to +// or read from, and to check the err result to ensure the operation +// completed successfully. +// +// The following example will print the first 8192 bytes from the file: +// +// file, err := db.GridFS("fs").Open("myfile.txt") +// check(err) +// b := make([]byte, 8192) +// n, err := file.Read(b) +// check(err) +// fmt.Println(string(b)) +// check(err) +// err = file.Close() +// check(err) +// fmt.Printf("%d bytes read\n", n) +// +// The io.Reader interface is implemented by *GridFile and may be used to +// deal with it. As an example, the following snippet will dump the whole +// file into the standard output: +// +// file, err := db.GridFS("fs").Open("myfile.txt") +// check(err) +// err = io.Copy(os.Stdout, file) +// check(err) +// err = file.Close() +// check(err) +// +func (gfs *GridFS) Open(name string) (file *GridFile, err error) { + var doc gfsFile + err = gfs.Files.Find(bson.M{"filename": name}).Sort("-uploadDate").One(&doc) + if err != nil { + return + } + file = gfs.newFile() + file.mode = gfsReading + file.doc = doc + return +} + +// OpenNext opens the next file from iter for reading, sets *file to it, +// and returns true on the success case. If no more documents are available +// on iter or an error occurred, *file is set to nil and the result is false. +// Errors will be available via iter.Err(). +// +// The iter parameter must be an iterator on the GridFS files collection. +// Using the GridFS.Find method is an easy way to obtain such an iterator, +// but any iterator on the collection will work. +// +// If the provided *file is non-nil, OpenNext will close it before attempting +// to iterate to the next element. This means that in a loop one only +// has to worry about closing files when breaking out of the loop early +// (break, return, or panic). +// +// For example: +// +// gfs := db.GridFS("fs") +// query := gfs.Find(nil).Sort("filename") +// iter := query.Iter() +// var f *mgo.GridFile +// for gfs.OpenNext(iter, &f) { +// fmt.Printf("Filename: %s\n", f.Name()) +// } +// if iter.Close() != nil { +// panic(iter.Close()) +// } +// +func (gfs *GridFS) OpenNext(iter *Iter, file **GridFile) bool { + if *file != nil { + // Ignoring the error here shouldn't be a big deal + // as we're reading the file and the loop iteration + // for this file is finished. + _ = (*file).Close() + } + var doc gfsFile + if !iter.Next(&doc) { + *file = nil + return false + } + f := gfs.newFile() + f.mode = gfsReading + f.doc = doc + *file = f + return true +} + +// Find runs query on GridFS's files collection and returns +// the resulting Query. +// +// This logic: +// +// gfs := db.GridFS("fs") +// iter := gfs.Find(nil).Iter() +// +// Is equivalent to: +// +// files := db.C("fs" + ".files") +// iter := files.Find(nil).Iter() +// +func (gfs *GridFS) Find(query interface{}) *Query { + return gfs.Files.Find(query) +} + +// RemoveId deletes the file with the provided id from the GridFS. +func (gfs *GridFS) RemoveId(id interface{}) error { + err := gfs.Files.Remove(bson.M{"_id": id}) + if err != nil { + return err + } + _, err = gfs.Chunks.RemoveAll(bson.D{{"files_id", id}}) + return err +} + +type gfsDocId struct { + Id interface{} "_id" +} + +// Remove deletes all files with the provided name from the GridFS. +func (gfs *GridFS) Remove(name string) (err error) { + iter := gfs.Files.Find(bson.M{"filename": name}).Select(bson.M{"_id": 1}).Iter() + var doc gfsDocId + for iter.Next(&doc) { + if e := gfs.RemoveId(doc.Id); e != nil { + err = e + } + } + if err == nil { + err = iter.Close() + } + return err +} + +func (file *GridFile) assertMode(mode gfsFileMode) { + switch file.mode { + case mode: + return + case gfsWriting: + panic("GridFile is open for writing") + case gfsReading: + panic("GridFile is open for reading") + case gfsClosed: + panic("GridFile is closed") + default: + panic("internal error: missing GridFile mode") + } +} + +// SetChunkSize sets size of saved chunks. Once the file is written to, it +// will be split in blocks of that size and each block saved into an +// independent chunk document. The default chunk size is 255kb. +// +// It is a runtime error to call this function once the file has started +// being written to. +func (file *GridFile) SetChunkSize(bytes int) { + file.assertMode(gfsWriting) + debugf("GridFile %p: setting chunk size to %d", file, bytes) + file.m.Lock() + file.doc.ChunkSize = bytes + file.m.Unlock() +} + +// Id returns the current file Id. +func (file *GridFile) Id() interface{} { + return file.doc.Id +} + +// SetId changes the current file Id. +// +// It is a runtime error to call this function once the file has started +// being written to, or when the file is not open for writing. +func (file *GridFile) SetId(id interface{}) { + file.assertMode(gfsWriting) + file.m.Lock() + file.doc.Id = id + file.m.Unlock() +} + +// Name returns the optional file name. An empty string will be returned +// in case it is unset. +func (file *GridFile) Name() string { + return file.doc.Filename +} + +// SetName changes the optional file name. An empty string may be used to +// unset it. +// +// It is a runtime error to call this function when the file is not open +// for writing. +func (file *GridFile) SetName(name string) { + file.assertMode(gfsWriting) + file.m.Lock() + file.doc.Filename = name + file.m.Unlock() +} + +// ContentType returns the optional file content type. An empty string will be +// returned in case it is unset. +func (file *GridFile) ContentType() string { + return file.doc.ContentType +} + +// ContentType changes the optional file content type. An empty string may be +// used to unset it. +// +// It is a runtime error to call this function when the file is not open +// for writing. +func (file *GridFile) SetContentType(ctype string) { + file.assertMode(gfsWriting) + file.m.Lock() + file.doc.ContentType = ctype + file.m.Unlock() +} + +// GetMeta unmarshals the optional "metadata" field associated with the +// file into the result parameter. The meaning of keys under that field +// is user-defined. For example: +// +// result := struct{ INode int }{} +// err = file.GetMeta(&result) +// if err != nil { +// panic(err.String()) +// } +// fmt.Printf("inode: %d\n", result.INode) +// +func (file *GridFile) GetMeta(result interface{}) (err error) { + file.m.Lock() + if file.doc.Metadata != nil { + err = bson.Unmarshal(file.doc.Metadata.Data, result) + } + file.m.Unlock() + return +} + +// SetMeta changes the optional "metadata" field associated with the +// file. The meaning of keys under that field is user-defined. +// For example: +// +// file.SetMeta(bson.M{"inode": inode}) +// +// It is a runtime error to call this function when the file is not open +// for writing. +func (file *GridFile) SetMeta(metadata interface{}) { + file.assertMode(gfsWriting) + data, err := bson.Marshal(metadata) + file.m.Lock() + if err != nil && file.err == nil { + file.err = err + } else { + file.doc.Metadata = &bson.Raw{Data: data} + } + file.m.Unlock() +} + +// Size returns the file size in bytes. +func (file *GridFile) Size() (bytes int64) { + file.m.Lock() + bytes = file.doc.Length + file.m.Unlock() + return +} + +// MD5 returns the file MD5 as a hex-encoded string. +func (file *GridFile) MD5() (md5 string) { + return file.doc.MD5 +} + +// UploadDate returns the file upload time. +func (file *GridFile) UploadDate() time.Time { + return file.doc.UploadDate +} + +// SetUploadDate changes the file upload time. +// +// It is a runtime error to call this function when the file is not open +// for writing. +func (file *GridFile) SetUploadDate(t time.Time) { + file.assertMode(gfsWriting) + file.m.Lock() + file.doc.UploadDate = t + file.m.Unlock() +} + +// Close flushes any pending changes in case the file is being written +// to, waits for any background operations to finish, and closes the file. +// +// It's important to Close files whether they are being written to +// or read from, and to check the err result to ensure the operation +// completed successfully. +func (file *GridFile) Close() (err error) { + file.m.Lock() + defer file.m.Unlock() + if file.mode == gfsWriting { + if len(file.wbuf) > 0 && file.err == nil { + file.insertChunk(file.wbuf) + file.wbuf = file.wbuf[0:0] + } + file.completeWrite() + } else if file.mode == gfsReading && file.rcache != nil { + file.rcache.wait.Lock() + file.rcache = nil + } + file.mode = gfsClosed + debugf("GridFile %p: closed", file) + return file.err +} + +func (file *GridFile) completeWrite() { + for file.wpending > 0 { + debugf("GridFile %p: waiting for %d pending chunks to complete file write", file, file.wpending) + file.c.Wait() + } + if file.err == nil { + hexsum := hex.EncodeToString(file.wsum.Sum(nil)) + if file.doc.UploadDate.IsZero() { + file.doc.UploadDate = bson.Now() + } + file.doc.MD5 = hexsum + file.err = file.gfs.Files.Insert(file.doc) + } + if file.err != nil { + file.gfs.Chunks.RemoveAll(bson.D{{"files_id", file.doc.Id}}) + } + if file.err == nil { + index := Index{ + Key: []string{"files_id", "n"}, + Unique: true, + } + file.err = file.gfs.Chunks.EnsureIndex(index) + } +} + +// Abort cancels an in-progress write, preventing the file from being +// automically created and ensuring previously written chunks are +// removed when the file is closed. +// +// It is a runtime error to call Abort when the file was not opened +// for writing. +func (file *GridFile) Abort() { + if file.mode != gfsWriting { + panic("file.Abort must be called on file opened for writing") + } + file.err = errors.New("write aborted") +} + +// Write writes the provided data to the file and returns the +// number of bytes written and an error in case something +// wrong happened. +// +// The file will internally cache the data so that all but the last +// chunk sent to the database have the size defined by SetChunkSize. +// This also means that errors may be deferred until a future call +// to Write or Close. +// +// The parameters and behavior of this function turn the file +// into an io.Writer. +func (file *GridFile) Write(data []byte) (n int, err error) { + file.assertMode(gfsWriting) + file.m.Lock() + debugf("GridFile %p: writing %d bytes", file, len(data)) + defer file.m.Unlock() + + if file.err != nil { + return 0, file.err + } + + n = len(data) + file.doc.Length += int64(n) + chunkSize := file.doc.ChunkSize + + if len(file.wbuf)+len(data) < chunkSize { + file.wbuf = append(file.wbuf, data...) + return + } + + // First, flush file.wbuf complementing with data. + if len(file.wbuf) > 0 { + missing := chunkSize - len(file.wbuf) + if missing > len(data) { + missing = len(data) + } + file.wbuf = append(file.wbuf, data[:missing]...) + data = data[missing:] + file.insertChunk(file.wbuf) + file.wbuf = file.wbuf[0:0] + } + + // Then, flush all chunks from data without copying. + for len(data) > chunkSize { + size := chunkSize + if size > len(data) { + size = len(data) + } + file.insertChunk(data[:size]) + data = data[size:] + } + + // And append the rest for a future call. + file.wbuf = append(file.wbuf, data...) + + return n, file.err +} + +func (file *GridFile) insertChunk(data []byte) { + n := file.chunk + file.chunk++ + debugf("GridFile %p: adding to checksum: %q", file, string(data)) + file.wsum.Write(data) + + for file.doc.ChunkSize*file.wpending >= 1024*1024 { + // Hold on.. we got a MB pending. + file.c.Wait() + if file.err != nil { + return + } + } + + file.wpending++ + + debugf("GridFile %p: inserting chunk %d with %d bytes", file, n, len(data)) + + // We may not own the memory of data, so rather than + // simply copying it, we'll marshal the document ahead of time. + data, err := bson.Marshal(gfsChunk{bson.NewObjectId(), file.doc.Id, n, data}) + if err != nil { + file.err = err + return + } + + go func() { + err := file.gfs.Chunks.Insert(bson.Raw{Data: data}) + file.m.Lock() + file.wpending-- + if err != nil && file.err == nil { + file.err = err + } + file.c.Broadcast() + file.m.Unlock() + }() +} + +// Seek sets the offset for the next Read or Write on file to +// offset, interpreted according to whence: 0 means relative to +// the origin of the file, 1 means relative to the current offset, +// and 2 means relative to the end. It returns the new offset and +// an error, if any. +func (file *GridFile) Seek(offset int64, whence int) (pos int64, err error) { + file.m.Lock() + debugf("GridFile %p: seeking for %s (whence=%d)", file, offset, whence) + defer file.m.Unlock() + switch whence { + case os.SEEK_SET: + case os.SEEK_CUR: + offset += file.offset + case os.SEEK_END: + offset += file.doc.Length + default: + panic("unsupported whence value") + } + if offset > file.doc.Length { + return file.offset, errors.New("seek past end of file") + } + if offset == file.doc.Length { + // If we're seeking to the end of the file, + // no need to read anything. This enables + // a client to find the size of the file using only the + // io.ReadSeeker interface with low overhead. + file.offset = offset + return file.offset, nil + } + chunk := int(offset / int64(file.doc.ChunkSize)) + if chunk+1 == file.chunk && offset >= file.offset { + file.rbuf = file.rbuf[int(offset-file.offset):] + file.offset = offset + return file.offset, nil + } + file.offset = offset + file.chunk = chunk + file.rbuf = nil + file.rbuf, err = file.getChunk() + if err == nil { + file.rbuf = file.rbuf[int(file.offset-int64(chunk)*int64(file.doc.ChunkSize)):] + } + return file.offset, err +} + +// Read reads into b the next available data from the file and +// returns the number of bytes written and an error in case +// something wrong happened. At the end of the file, n will +// be zero and err will be set to io.EOF. +// +// The parameters and behavior of this function turn the file +// into an io.Reader. +func (file *GridFile) Read(b []byte) (n int, err error) { + file.assertMode(gfsReading) + file.m.Lock() + debugf("GridFile %p: reading at offset %d into buffer of length %d", file, file.offset, len(b)) + defer file.m.Unlock() + if file.offset == file.doc.Length { + return 0, io.EOF + } + for err == nil { + i := copy(b, file.rbuf) + n += i + file.offset += int64(i) + file.rbuf = file.rbuf[i:] + if i == len(b) || file.offset == file.doc.Length { + break + } + b = b[i:] + file.rbuf, err = file.getChunk() + } + return n, err +} + +func (file *GridFile) getChunk() (data []byte, err error) { + cache := file.rcache + file.rcache = nil + if cache != nil && cache.n == file.chunk { + debugf("GridFile %p: Getting chunk %d from cache", file, file.chunk) + cache.wait.Lock() + data, err = cache.data, cache.err + } else { + debugf("GridFile %p: Fetching chunk %d", file, file.chunk) + var doc gfsChunk + err = file.gfs.Chunks.Find(bson.D{{"files_id", file.doc.Id}, {"n", file.chunk}}).One(&doc) + data = doc.Data + } + file.chunk++ + if int64(file.chunk)*int64(file.doc.ChunkSize) < file.doc.Length { + // Read the next one in background. + cache = &gfsCachedChunk{n: file.chunk} + cache.wait.Lock() + debugf("GridFile %p: Scheduling chunk %d for background caching", file, file.chunk) + // Clone the session to avoid having it closed in between. + chunks := file.gfs.Chunks + session := chunks.Database.Session.Clone() + go func(id interface{}, n int) { + defer session.Close() + chunks = chunks.With(session) + var doc gfsChunk + cache.err = chunks.Find(bson.D{{"files_id", id}, {"n", n}}).One(&doc) + cache.data = doc.Data + cache.wait.Unlock() + }(file.doc.Id, file.chunk) + file.rcache = cache + } + debugf("Returning err: %#v", err) + return +} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/LICENSE b/vendor/gopkg.in/mgo.v2/internal/json/LICENSE new file mode 100644 index 000000000..744875676 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/internal/json/LICENSE @@ -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/gopkg.in/mgo.v2/internal/json/decode.go b/vendor/gopkg.in/mgo.v2/internal/json/decode.go new file mode 100644 index 000000000..ce7c7d249 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/internal/json/decode.go @@ -0,0 +1,1685 @@ +// Copyright 2010 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. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "errors" + "fmt" + "reflect" + "runtime" + "strconv" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. +// Unmarshal will only set exported fields of the struct. +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores key- +// value pairs from the JSON object into the map. The map's key type must +// either be a string or implement encoding.TextUnmarshaler. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +// +func Unmarshal(data []byte, v interface{}) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes +} + +func (e *UnmarshalTypeError) Error() string { + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// (No longer used; kept for compatibility.) +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Ptr { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v interface{}) (err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + err = r.(error) + } + }() + + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + d.value(rv) + return d.savedError +} + +// A Number represents a JSON number literal. +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) +} + +// isValidNumber reports whether s is a valid JSON number literal. +func isValidNumber(s string) bool { + // This function implements the JSON numbers grammar. + // See https://tools.ietf.org/html/rfc7159#section-6 + // and http://json.org/number.gif + + if s == "" { + return false + } + + // Optional - + if s[0] == '-' { + s = s[1:] + if s == "" { + return false + } + } + + // Digits + switch { + default: + return false + + case s[0] == '0': + s = s[1:] + + case '1' <= s[0] && s[0] <= '9': + s = s[1:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // . followed by 1 or more digits. + if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { + s = s[2:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { + s = s[1:] + if s[0] == '+' || s[0] == '-' { + s = s[1:] + if s == "" { + return false + } + } + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + } + } + + // Make sure we are at the end. + return s == "" +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // read offset in data + scan scanner + nextscan scanner // for calls to nextValue + savedError error + useNumber bool + ext Extension +} + +// errPhase is used for errors that should not happen unless +// there is a bug in the JSON decoder or something is editing +// the data slice while the decoder executes. +var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?") + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + return d +} + +// error aborts the decoding by panicking with err. +func (d *decodeState) error(err error) { + panic(err) +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = err + } +} + +// next cuts off and returns the next full JSON value in d.data[d.off:]. +// The next value is known to be an object or array, not a literal. +func (d *decodeState) next() []byte { + c := d.data[d.off] + item, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // Our scanner has seen the opening brace/bracket + // and thinks we're still in the middle of the object. + // invent a closing brace/bracket to get it out. + if c == '{' { + d.scan.step(&d.scan, '}') + } else if c == '[' { + d.scan.step(&d.scan, ']') + } else { + // Was inside a function name. Get out of it. + d.scan.step(&d.scan, '(') + d.scan.step(&d.scan, ')') + } + + return item +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +// It updates d.off and returns the new scan code. +func (d *decodeState) scanWhile(op int) int { + var newOp int + for { + if d.off >= len(d.data) { + newOp = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } else { + c := d.data[d.off] + d.off++ + newOp = d.scan.step(&d.scan, c) + } + if newOp != op { + break + } + } + return newOp +} + +// value decodes a JSON value from d.data[d.off:] into the value. +// it updates d.off to point past the decoded value. +func (d *decodeState) value(v reflect.Value) { + if !v.IsValid() { + _, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // d.scan thinks we're still at the beginning of the item. + // Feed in an empty string - the shortest, simplest value - + // so that it knows we got to the end of the value. + if d.scan.redo { + // rewind. + d.scan.redo = false + d.scan.step = stateBeginValue + } + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + + n := len(d.scan.parseState) + if n > 0 && d.scan.parseState[n-1] == parseObjectKey { + // d.scan thinks we just read an object key; finish the object + d.scan.step(&d.scan, ':') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '}') + } + + return + } + + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(v) + + case scanBeginObject: + d.object(v) + + case scanBeginLiteral: + d.literal(v) + + case scanBeginName: + d.name(v) + } +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() interface{} { + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(reflect.Value{}) + + case scanBeginObject: + d.object(reflect.Value{}) + + case scanBeginName: + switch v := d.nameInterface().(type) { + case nil, string: + return v + } + + case scanBeginLiteral: + switch v := d.literalInterface().(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// 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 (d *decodeState) indirect(v reflect.Value, decodingNull bool) (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() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, v + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, v + } + } + v = v.Elem() + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into the value v. +// the first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) { + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) + d.off-- + d.next() + return + } + + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + v.Set(reflect.ValueOf(d.arrayInterface())) + return + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) + d.off-- + d.next() + return + case reflect.Array: + case reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + d.value(v.Index(i)) + } else { + // Ran out of fixed array: skip. + d.value(reflect.Value{}) + } + i++ + + // Next token must be , or ]. + op = d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + if op != scanArrayValue { + d.error(errPhase) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into the value v. +// the first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) { + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if d.storeKeyed(pv) { + return + } + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + v = pv + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + v.Set(reflect.ValueOf(d.objectInterface())) + return + } + + // Check type of target: + // struct or + // map[string]T or map[encoding.TextUnmarshaler]T + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind or be an encoding.TextUnmarshaler. + t := v.Type() + if t.Key().Kind() != reflect.String && + !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + + default: + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + + var mapElem reflect.Value + + empty := true + for { + // Read opening " of string key or closing }. + op := d.scanWhile(scanSkipSpace) + if op == scanEndObject { + if !empty && !d.ext.trailingCommas { + d.syntaxError("beginning of object key string") + } + break + } + empty = false + if op == scanBeginName { + if !d.ext.unquotedKeys { + d.syntaxError("beginning of object key string") + } + } else if op != scanBeginLiteral { + d.error(errPhase) + } + unquotedKey := op == scanBeginName + + // Read key. + start := d.off - 1 + op = d.scanWhile(scanContinue) + item := d.data[start : d.off-1] + var key []byte + if unquotedKey { + key = item + // TODO Fix code below to quote item when necessary. + } else { + var ok bool + key, ok = unquoteBytes(item) + if !ok { + d.error(errPhase) + } + } + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, key) { + f = ff + break + } + if f == nil && ff.equalFold(ff.nameBytes, key) { + f = ff + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + } + } + + // Read : before value. + if op == scanSkipSpace { + op = d.scanWhile(scanSkipSpace) + } + if op != scanObjectKey { + d.error(errPhase) + } + + // Read value. + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + d.literalStore(nullLiteral, subv, false) + case string: + d.literalStore([]byte(qv), subv, true) + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + d.value(subv) + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := v.Type().Key() + var kv reflect.Value + switch { + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(v.Type().Key()) + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(v.Type().Key()) + d.literalStore(item, kv, true) + kv = kv.Elem() + default: + panic("json: Unexpected key type") // should never occur + } + v.SetMapIndex(kv, subv) + } + + // Next token must be , or }. + op = d.scanWhile(scanSkipSpace) + if op == scanEndObject { + break + } + if op != scanObjectValue { + d.error(errPhase) + } + } +} + +// isNull returns whether there's a null literal at the provided offset. +func (d *decodeState) isNull(off int) bool { + if off+4 >= len(d.data) || d.data[off] != 'n' || d.data[off+1] != 'u' || d.data[off+2] != 'l' || d.data[off+3] != 'l' { + return false + } + d.nextscan.reset() + for i, c := range d.data[off:] { + if i > 4 { + return false + } + switch d.nextscan.step(&d.nextscan, c) { + case scanContinue, scanBeginName: + continue + } + break + } + return true +} + +// name consumes a const or function from d.data[d.off-1:], decoding into the value v. +// the first byte of the function name has been read already. +func (d *decodeState) name(v reflect.Value) { + if d.isNull(d.off-1) { + d.literal(v) + return + } + + // Check for unmarshaler. + u, ut, pv := d.indirect(v, false) + if d.storeKeyed(pv) { + return + } + if u != nil { + d.off-- + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over function in input + return + } + v = pv + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + out := d.nameInterface() + if out == nil { + v.Set(reflect.Zero(v.Type())) + } else { + v.Set(reflect.ValueOf(out)) + } + return + } + + nameStart := d.off - 1 + + op := d.scanWhile(scanContinue) + + name := d.data[nameStart : d.off-1] + if op != scanParam { + // Back up so the byte just read is consumed next. + d.off-- + d.scan.undo(op) + if l, ok := d.convertLiteral(name); ok { + d.storeValue(v, l) + return + } + d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) + } + + funcName := string(name) + funcData := d.ext.funcs[funcName] + if funcData.key == "" { + d.error(fmt.Errorf("json: unknown function %q", funcName)) + } + + // Check type of target: + // struct or + // map[string]T or map[encoding.TextUnmarshaler]T + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind or be an encoding.TextUnmarshaler. + t := v.Type() + if t.Key().Kind() != reflect.String && + !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + + default: + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } + + // TODO Fix case of func field as map. + //topv := v + + // Figure out field corresponding to function. + key := []byte(funcData.key) + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + v = reflect.New(elemType).Elem() + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, key) { + f = ff + break + } + if f == nil && ff.equalFold(ff.nameBytes, key) { + f = ff + } + } + if f != nil { + for _, i := range f.index { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + v = v.Field(i) + } + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + } + } + + // Check for unmarshaler on func field itself. + u, ut, pv = d.indirect(v, false) + if u != nil { + d.off = nameStart + err := u.UnmarshalJSON(d.next()) + if err != nil { + d.error(err) + } + return + } + + var mapElem reflect.Value + + // Parse function arguments. + for i := 0; ; i++ { + // closing ) - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + if i >= len(funcData.args) { + d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) + } + key := []byte(funcData.args[i]) + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if bytes.Equal(ff.nameBytes, key) { + f = ff + break + } + if f == nil && ff.equalFold(ff.nameBytes, key) { + f = ff + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + } + } + + // Read value. + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + d.literalStore(nullLiteral, subv, false) + case string: + d.literalStore([]byte(qv), subv, true) + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + d.value(subv) + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := v.Type().Key() + var kv reflect.Value + switch { + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(v.Type().Key()) + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(v.Type().Key()) + d.literalStore(key, kv, true) + kv = kv.Elem() + default: + panic("json: Unexpected key type") // should never occur + } + v.SetMapIndex(kv, subv) + } + + // Next token must be , or ). + op = d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + if op != scanParam { + d.error(errPhase) + } + } +} + +// keyed attempts to decode an object or function using a keyed doc extension, +// and returns the value and true on success, or nil and false otherwise. +func (d *decodeState) keyed() (interface{}, bool) { + if len(d.ext.keyed) == 0 { + return nil, false + } + + unquote := false + + // Look-ahead first key to check for a keyed document extension. + d.nextscan.reset() + var start, end int + for i, c := range d.data[d.off-1:] { + switch op := d.nextscan.step(&d.nextscan, c); op { + case scanSkipSpace, scanContinue, scanBeginObject: + continue + case scanBeginLiteral, scanBeginName: + unquote = op == scanBeginLiteral + start = i + continue + } + end = i + break + } + + name := d.data[d.off-1+start : d.off-1+end] + + var key []byte + var ok bool + if unquote { + key, ok = unquoteBytes(name) + if !ok { + d.error(errPhase) + } + } else { + funcData, ok := d.ext.funcs[string(name)] + if !ok { + return nil, false + } + key = []byte(funcData.key) + } + + decode, ok := d.ext.keyed[string(key)] + if !ok { + return nil, false + } + + d.off-- + out, err := decode(d.next()) + if err != nil { + d.error(err) + } + return out, true +} + +func (d *decodeState) storeKeyed(v reflect.Value) bool { + keyed, ok := d.keyed() + if !ok { + return false + } + d.storeValue(v, keyed) + return true +} + +var ( + trueBytes = []byte("true") + falseBytes = []byte("false") + nullBytes = []byte("null") +) + +func (d *decodeState) storeValue(v reflect.Value, from interface{}) { + switch from { + case nil: + d.literalStore(nullBytes, v, false) + return + case true: + d.literalStore(trueBytes, v, false) + return + case false: + d.literalStore(falseBytes, v, false) + return + } + fromv := reflect.ValueOf(from) + for fromv.Kind() == reflect.Ptr && !fromv.IsNil() { + fromv = fromv.Elem() + } + fromt := fromv.Type() + for v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + vt := v.Type() + if fromt.AssignableTo(vt) { + v.Set(fromv) + } else if fromt.ConvertibleTo(vt) { + v.Set(fromv.Convert(vt)) + } else { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + } +} + +func (d *decodeState) convertLiteral(name []byte) (interface{}, bool) { + if len(name) == 0 { + return nil, false + } + switch name[0] { + case 't': + if bytes.Equal(name, trueBytes) { + return true, true + } + case 'f': + if bytes.Equal(name, falseBytes) { + return false, true + } + case 'n': + if bytes.Equal(name, nullBytes) { + return nil, true + } + } + if l, ok := d.ext.consts[string(name)]; ok { + return l, true + } + return nil, false +} + +// literal consumes a literal from d.data[d.off-1:], decoding into the value v. +// The first byte of the literal has been read already +// (that's how the caller knows it's a literal). +func (d *decodeState) literal(v reflect.Value) { + // All bytes inside literal return scanContinue op code. + start := d.off - 1 + op := d.scanWhile(scanContinue) + + // Scan read one byte too far; back up. + d.off-- + d.scan.undo(op) + + d.literalStore(d.data[start:d.off], v, false) +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (interface{}, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return + } + wantptr := item[0] == 'n' // null + u, ut, pv := d.indirect(v, wantptr) + if u != nil { + err := u.UnmarshalJSON(item) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + } + return + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + err := ut.UnmarshalText(s) + if err != nil { + d.error(err) + } + return + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + switch v.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := c == 't' + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(errPhase) + } + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + v.SetString(s) + if !isValidNumber(s) { + d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) + } + break + } + if fromQuoted { + d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) + } + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) + break + } + v.SetFloat(n) + } + } +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() interface{} { + switch d.scanWhile(scanSkipSpace) { + default: + d.error(errPhase) + panic("unreachable") + case scanBeginArray: + return d.arrayInterface() + case scanBeginObject: + return d.objectInterface() + case scanBeginLiteral: + return d.literalInterface() + case scanBeginName: + return d.nameInterface() + } +} + +func (d *decodeState) syntaxError(expected string) { + msg := fmt.Sprintf("invalid character '%c' looking for %s", d.data[d.off-1], expected) + d.error(&SyntaxError{msg, int64(d.off)}) +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []interface{} { + var v = make([]interface{}, 0) + for { + // Look ahead for ] - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndArray { + if len(v) > 0 && !d.ext.trailingCommas { + d.syntaxError("beginning of value") + } + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + op = d.scanWhile(scanSkipSpace) + if op == scanEndArray { + break + } + if op != scanArrayValue { + d.error(errPhase) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() interface{} { + v, ok := d.keyed() + if ok { + return v + } + + m := make(map[string]interface{}) + for { + // Read opening " of string key or closing }. + op := d.scanWhile(scanSkipSpace) + if op == scanEndObject { + if len(m) > 0 && !d.ext.trailingCommas { + d.syntaxError("beginning of object key string") + } + break + } + if op == scanBeginName { + if !d.ext.unquotedKeys { + d.syntaxError("beginning of object key string") + } + } else if op != scanBeginLiteral { + d.error(errPhase) + } + unquotedKey := op == scanBeginName + + // Read string key. + start := d.off - 1 + op = d.scanWhile(scanContinue) + item := d.data[start : d.off-1] + var key string + if unquotedKey { + key = string(item) + } else { + var ok bool + key, ok = unquote(item) + if !ok { + d.error(errPhase) + } + } + + // Read : before value. + if op == scanSkipSpace { + op = d.scanWhile(scanSkipSpace) + } + if op != scanObjectKey { + d.error(errPhase) + } + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + op = d.scanWhile(scanSkipSpace) + if op == scanEndObject { + break + } + if op != scanObjectValue { + d.error(errPhase) + } + } + return m +} + +// literalInterface is like literal but returns an interface value. +func (d *decodeState) literalInterface() interface{} { + // All bytes inside literal return scanContinue op code. + start := d.off - 1 + op := d.scanWhile(scanContinue) + + // Scan read one byte too far; back up. + d.off-- + d.scan.undo(op) + item := d.data[start:d.off] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + d.error(errPhase) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + d.error(errPhase) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// nameInterface is like function but returns map[string]interface{}. +func (d *decodeState) nameInterface() interface{} { + v, ok := d.keyed() + if ok { + return v + } + + nameStart := d.off - 1 + + op := d.scanWhile(scanContinue) + + name := d.data[nameStart : d.off-1] + if op != scanParam { + // Back up so the byte just read is consumed next. + d.off-- + d.scan.undo(op) + if l, ok := d.convertLiteral(name); ok { + return l + } + d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) + } + + funcName := string(name) + funcData := d.ext.funcs[funcName] + if funcData.key == "" { + d.error(fmt.Errorf("json: unknown function %q", funcName)) + } + + m := make(map[string]interface{}) + for i := 0; ; i++ { + // Look ahead for ) - can only happen on first iteration. + op := d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + + // Back up so d.value can have the byte we just read. + d.off-- + d.scan.undo(op) + + if i >= len(funcData.args) { + d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) + } + m[funcData.args[i]] = d.valueInterface() + + // Next token must be , or ). + op = d.scanWhile(scanSkipSpace) + if op == scanEndParams { + break + } + if op != scanParam { + d.error(errPhase) + } + } + return map[string]interface{}{funcData.key: m} +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + r, err := strconv.ParseUint(string(s[2:6]), 16, 64) + if err != nil { + return -1 + } + return rune(r) +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/encode.go b/vendor/gopkg.in/mgo.v2/internal/json/encode.go new file mode 100644 index 000000000..67a0f0062 --- /dev/null +++ b/vendor/gopkg.in/mgo.v2/internal/json/encode.go @@ -0,0 +1,1256 @@ +// Copyright 2010 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 json implements encoding and decoding of JSON as defined in +// RFC 4627. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" +// to keep some browsers from misinterpreting JSON output as HTML. +// Ampersand "&" is also escaped to "\u0026" for the same reason. +// This escaping can be disabled using an Encoder with DisableHTMLEscaping. +// +// Array and slice values encode as JSON arrays, except that +// []byte encodes as a base64-encoded string, and a nil slice +// encodes as the null JSON value. +// +// Struct values encode as JSON objects. Each exported struct field +// becomes a member of the object unless +// - the field's tag is "-", or +// - the field is empty and its tag specifies the "omitempty" option. +// The empty values are false, 0, any +// nil pointer or interface value, and any array, slice, map, or string of +// length zero. The object's default key string is the struct field name +// but can be specified in the struct field's tag value. The "json" key in +// the struct field's tag value is the key name, followed by an optional comma +// and options. Examples: +// +// // Field is ignored by this package. +// Field int `json:"-"` +// +// // Field appears in JSON as key "myName". +// Field int `json:"myName"` +// +// // Field appears in JSON as key "myName" and +// // the field is omitted from the object if its value is empty, +// // as defined above. +// Field int `json:"myName,omitempty"` +// +// // Field appears in JSON as key "Field" (the default), but +// // the field is skipped if empty. +// // Note the leading comma. +// Field int `json:",omitempty"` +// +// The "string" option signals that a field is stored as JSON inside a +// JSON-encoded string. It applies only to fields of string, floating point, +// integer, or boolean types. This extra level of encoding is sometimes used +// when communicating with JavaScript programs: +// +// Int64String int64 `json:",string"` +// +// The key name will be used if it's a non-empty string consisting of +// only Unicode letters, digits, dollar signs, percent signs, hyphens, +// underscores and slashes. +// +// Anonymous struct fields are usually marshaled as if their inner exported fields +// were fields in the outer struct, subject to the usual Go visibility rules amended +// as described in the next paragraph. +// An anonymous struct field with a name given in its JSON tag is treated as +// having that name, rather than being anonymous. +// An anonymous struct field of interface type is treated the same as having +// that type as its name, rather than being anonymous. +// +// The Go visibility rules for struct fields are amended for JSON when +// deciding which field to marshal or unmarshal. If there are +// multiple fields at the same level, and that level is the least +// nested (and would therefore be the nesting level selected by the +// usual Go rules), the following extra rules apply: +// +// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, +// even if there are multiple untagged fields that would otherwise conflict. +// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. +// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. +// +// Handling of anonymous struct fields is new in Go 1.1. +// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of +// an anonymous struct field in both current and earlier versions, give the field +// a JSON tag of "-". +// +// Map values encode as JSON objects. The map's key type must either be a string +// or implement encoding.TextMarshaler. The map keys are used as JSON object +// keys, subject to the UTF-8 coercion described for string values above. +// +// Pointer values encode as the value pointed to. +// A nil pointer encodes as the null JSON value. +// +// Interface values encode as the value contained in the interface. +// A nil interface value encodes as the null JSON value. +// +// Channel, complex, and function values cannot be encoded in JSON. +// Attempting to encode such a value causes Marshal to return +// an UnsupportedTypeError. +// +// JSON cannot represent cyclic data structures and Marshal does not +// handle them. Passing cyclic structures to Marshal will result in +// an infinite recursion. +// +func Marshal(v interface{}) ([]byte, error) { + e := &encodeState{} + err := e.marshal(v, encOpts{escapeHTML: true}) + if err != nil { + return nil, err + } + return e.Bytes(), nil +} + +// MarshalIndent is like Marshal but applies Indent to format the output. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + b, err := Marshal(v) + if err != nil { + return nil, err + } + var buf bytes.Buffer + err = Indent(&buf, b, prefix, indent) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 +// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 +// so that the JSON will be safe to embed inside HTML